[packages/xfsprogs] - rel 3; important fixes from git (these will be in 3.2.1)

arekm arekm at pld-linux.org
Tue Jul 8 10:07:30 CEST 2014


commit 3d585810b809dcbcd72815e22177f65e1cec8853
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Tue Jul 8 10:07:25 2014 +0200

    - rel 3; important fixes from git (these will be in 3.2.1)

 xfsprogs-git.patch | 27180 +++++++++++++++++++++++++++++++++++++++++++++++++++
 xfsprogs.spec      |     6 +-
 2 files changed, 27184 insertions(+), 2 deletions(-)
---
diff --git a/xfsprogs.spec b/xfsprogs.spec
index fa7a906..1c280a3 100644
--- a/xfsprogs.spec
+++ b/xfsprogs.spec
@@ -6,12 +6,13 @@ Summary:	Tools for the XFS filesystem
 Summary(pl.UTF-8):	Narzędzia do systemu plików XFS
 Name:		xfsprogs
 Version:	3.2.0
-Release:	2
+Release:	3
 License:	LGPL v2.1 (libhandle), GPL v2 (the rest)
 Group:		Applications/System
 Source0:	ftp://linux-xfs.sgi.com/projects/xfs/cmd_tars/%{name}-%{version}.tar.gz
 # Source0-md5:	400047b2f6af87c0345b8f0cc00c13db
 Source1:	xfs_lsprojid
+Patch100:	%{name}-git.patch
 Patch0:		%{name}-miscfix-v2.patch
 Patch1:		%{name}-pl.po-update.patch
 Patch2:		%{name}-repair-tcmalloc.patch
@@ -93,8 +94,9 @@ Biblioteki statyczne do XFS.
 
 %prep
 %setup -q
+%patch100 -p1
 %patch0 -p1
-%patch1 -p1
+#%patch1 -p1
 
 %{?with_tcmalloc:%patch2 -p1}
 %patch3 -p1
diff --git a/xfsprogs-git.patch b/xfsprogs-git.patch
new file mode 100644
index 0000000..4b4f73a
--- /dev/null
+++ b/xfsprogs-git.patch
@@ -0,0 +1,27180 @@
+diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
+index 71adb57..7ce5ec9 100644
+--- a/copy/xfs_copy.c
++++ b/copy/xfs_copy.c
+@@ -217,25 +217,6 @@ handle_error:
+ }
+ 
+ void
+-killall(void)
+-{
+-	int i;
+-
+-	/* only the parent gets to kill things */
+-
+-	if (getpid() != parent_pid)
+-		return;
+-
+-	for (i = 0; i < num_targets; i++)  {
+-		if (target[i].state == ACTIVE)  {
+-			/* kill up target threads */
+-			pthread_kill(target[i].pid, SIGKILL);
+-			pthread_mutex_unlock(&targ[i].wait);
+-		}
+-	}
+-}
+-
+-void
+ handler(int sig)
+ {
+ 	pid_t	pid;
+@@ -400,8 +381,7 @@ read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
+ 	if (buf->length > buf->size)  {
+ 		do_warn(_("assert error:  buf->length = %d, buf->size = %d\n"),
+ 			buf->length, buf->size);
+-		killall();
+-		abort();
++		exit(1);
+ 	}
+ 
+ 	if ((res = read(fd, buf->data, buf->length)) < 0)  {
+@@ -594,11 +574,6 @@ main(int argc, char **argv)
+ 
+ 	parent_pid = getpid();
+ 
+-	if (atexit(killall))  {
+-		do_log(_("%s: couldn't register atexit function.\n"), progname);
+-		die_perror();
+-	}
+-
+ 	/* open up source -- is it a file? */
+ 
+ 	open_flags = O_RDONLY;
+@@ -725,7 +700,7 @@ main(int argc, char **argv)
+ 	if (source_blocksize > source_sectorsize)  {
+ 		/* get number of leftover sectors in last block of ag header */
+ 
+-		tmp_residue = ((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
++		tmp_residue = ((XFS_AGFL_DADDR(mp) + 1) * BBSIZE)
+ 					% source_blocksize;
+ 		first_residue = (tmp_residue == 0) ? 0 :
+ 			source_blocksize - tmp_residue;
+@@ -738,10 +713,10 @@ main(int argc, char **argv)
+ 		exit(1);
+ 	}
+ 
+-	first_agbno = (((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
++	first_agbno = (((XFS_AGFL_DADDR(mp) + 1) * BBSIZE)
+ 				+ first_residue) / source_blocksize;
+ 	ASSERT(first_agbno != 0);
+-	ASSERT( ((((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
++	ASSERT(((((XFS_AGFL_DADDR(mp) + 1) * BBSIZE)
+ 				+ first_residue) % source_blocksize) == 0);
+ 
+ 	/* now open targets */
+@@ -1177,9 +1152,6 @@ main(int argc, char **argv)
+ 	}
+ 
+ 	check_errors();
+-	killall();
+-	pthread_exit(NULL);
+-	/*NOTREACHED*/
+ 	return 0;
+ }
+ 
+diff --git a/db/Makefile b/db/Makefile
+index 9485b82..bae6154 100644
+--- a/db/Makefile
++++ b/db/Makefile
+@@ -14,7 +14,7 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
+ 	io.h malloc.h metadump.h output.h print.h quit.h sb.h sig.h strvec.h \
+ 	text.h type.h write.h attrset.h symlink.h
+ CFILES = $(HFILES:.h=.c)
+-LSRCFILES = xfs_admin.sh xfs_check.sh xfs_ncheck.sh xfs_metadump.sh
++LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh
+ 
+ LLDLIBS	= $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
+ LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
+@@ -38,7 +38,6 @@ install: default
+ 	$(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
+ 	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
+ 	$(INSTALL) -m 755 xfs_admin.sh $(PKG_SBIN_DIR)/xfs_admin
+-	$(INSTALL) -m 755 xfs_check.sh $(PKG_SBIN_DIR)/xfs_check
+ 	$(INSTALL) -m 755 xfs_ncheck.sh $(PKG_SBIN_DIR)/xfs_ncheck
+ 	$(INSTALL) -m 755 xfs_metadump.sh $(PKG_SBIN_DIR)/xfs_metadump
+ install-dev:
+diff --git a/db/agi.c b/db/agi.c
+index 398bdbb..6f167ac 100644
+--- a/db/agi.c
++++ b/db/agi.c
+@@ -57,6 +57,8 @@ const field_t	agi_flds[] = {
+ 	{ "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE },
+ 	{ "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
+ 	{ "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE },
++	{ "free_root", FLDT_AGBLOCK, OI(OFF(free_root)), C1, 0, TYP_INOBT },
++	{ "free_level", FLDT_UINT32D, OI(OFF(free_level)), C1, 0, TYP_NONE },
+ 	{ NULL }
+ };
+ 
+diff --git a/db/attrset.c b/db/attrset.c
+index 762b3bf..ea5261a 100644
+--- a/db/attrset.c
++++ b/db/attrset.c
+@@ -170,7 +170,7 @@ attr_set_f(
+ out:
+ 	mp->m_flags &= ~LIBXFS_MOUNT_COMPAT_ATTR;
+ 	if (ip)
+-		libxfs_iput(ip, 0);
++		IRELE(ip);
+ 	if (value)
+ 		free(value);
+ 	return 0;
+@@ -244,6 +244,6 @@ attr_remove_f(
+ out:
+ 	mp->m_flags &= ~LIBXFS_MOUNT_COMPAT_ATTR;
+ 	if (ip)
+-		libxfs_iput(ip, 0);
++		IRELE(ip);
+ 	return 0;
+ }
+diff --git a/db/btblock.c b/db/btblock.c
+index 1ea0cff..cdb8b1d 100644
+--- a/db/btblock.c
++++ b/db/btblock.c
+@@ -60,6 +60,12 @@ struct xfs_db_btree {
+ 		sizeof(xfs_inobt_rec_t),
+ 		sizeof(__be32),
+ 	},
++	{	XFS_FIBT_MAGIC,
++		XFS_BTREE_SBLOCK_LEN,
++		sizeof(xfs_inobt_key_t),
++		sizeof(xfs_inobt_rec_t),
++		sizeof(__be32),
++	},
+ 	{	XFS_BMAP_CRC_MAGIC,
+ 		XFS_BTREE_LBLOCK_CRC_LEN,
+ 		sizeof(xfs_bmbt_key_t),
+@@ -84,6 +90,12 @@ struct xfs_db_btree {
+ 		sizeof(xfs_inobt_rec_t),
+ 		sizeof(__be32),
+ 	},
++	{	XFS_FIBT_CRC_MAGIC,
++		XFS_BTREE_SBLOCK_CRC_LEN,
++		sizeof(xfs_inobt_key_t),
++		sizeof(xfs_inobt_rec_t),
++		sizeof(__be32),
++	},
+ 	{	0,
+ 	},
+ };
+diff --git a/db/metadump.c b/db/metadump.c
+index 09bb85a..38cd441 100644
+--- a/db/metadump.c
++++ b/db/metadump.c
+@@ -1917,6 +1917,7 @@ scanfunc_ino(
+ 	xfs_inobt_ptr_t		*pp;
+ 	int			i;
+ 	int			numrecs;
++	int			finobt = *(int *) arg;
+ 
+ 	numrecs = be16_to_cpu(block->bb_numrecs);
+ 
+@@ -1928,6 +1929,14 @@ scanfunc_ino(
+ 					typtab[btype].name, agno, agbno);
+ 			numrecs = mp->m_inobt_mxr[0];
+ 		}
++
++		/*
++		 * Only copy the btree blocks for the finobt. The inobt scan
++		 * copies the inode chunks.
++		 */
++		if (finobt)
++			return 1;
++
+ 		rp = XFS_INOBT_REC_ADDR(mp, block, 1);
+ 		for (i = 0; i < numrecs; i++, rp++) {
+ 			if (!copy_inode_chunk(agno, rp))
+@@ -1967,6 +1976,7 @@ copy_inodes(
+ {
+ 	xfs_agblock_t		root;
+ 	int			levels;
++	int			finobt = 0;
+ 
+ 	root = be32_to_cpu(agi->agi_root);
+ 	levels = be32_to_cpu(agi->agi_level);
+@@ -1985,7 +1995,20 @@ copy_inodes(
+ 		return 1;
+ 	}
+ 
+-	return scan_btree(agno, root, levels, TYP_INOBT, agi, scanfunc_ino);
++	if (!scan_btree(agno, root, levels, TYP_INOBT, &finobt, scanfunc_ino))
++		return 0;
++
++	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
++		root = be32_to_cpu(agi->agi_free_root);
++		levels = be32_to_cpu(agi->agi_free_level);
++
++		finobt = 1;
++		if (!scan_btree(agno, root, levels, TYP_INOBT, &finobt,
++				scanfunc_ino))
++			return 0;
++	}
++
++	return 1;
+ }
+ 
+ static int
+diff --git a/db/write.c b/db/write.c
+index ca8bd0f..0157a44 100644
+--- a/db/write.c
++++ b/db/write.c
+@@ -565,7 +565,7 @@ convert_arg(
+ 		return NULL;
+ 
+ 	/* Does the value fit into the range of the destination bitfield? */
+-	if ((val >> bit_length) > 0)
++	if (bit_length < 64 && (val >> bit_length) > 0)
+ 		return NULL;
+ 	/*
+ 	 * If the length of the field is not a multiple of a byte, push
+diff --git a/db/xfs_check.sh b/db/xfs_check.sh
+deleted file mode 100755
+index 553da63..0000000
+--- a/db/xfs_check.sh
++++ /dev/null
+@@ -1,42 +0,0 @@
+-#!/bin/sh -f
+-#
+-# Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+-#
+-
+-OPTS=" "
+-DBOPTS=" "
+-USAGE="Usage: xfs_check [-fsvV] [-l logdev] [-i ino]... [-b bno]... special"
+-
+-echo "xfs_check is deprecated and scheduled for removal in June 2014."
+-echo "Please use xfs_repair -n <dev> instead."
+-
+-while getopts "b:fi:l:stvV" c
+-do
+-	case $c in
+-	s)	OPTS=$OPTS"-s ";;
+-	t)	OPTS=$OPTS"-t ";;
+-	v)	OPTS=$OPTS"-v ";;
+-	i)	OPTS=$OPTS"-i "$OPTARG" ";;
+-	b)	OPTS=$OPTS"-b "$OPTARG" ";;
+-	f)	DBOPTS=$DBOPTS" -f";;
+-	l)	DBOPTS=$DBOPTS" -l "$OPTARG" ";;
+-	V)	xfs_db -p xfs_check -V
+-		status=$?
+-		exit $status
+-		;;
+-	\?)	echo $USAGE 1>&2
+-		exit 2
+-		;;
+-	esac
+-done
+-set -- extra $@
+-shift $OPTIND
+-case $# in
+-	1)	xfs_db$DBOPTS -F -i -p xfs_check -c "check$OPTS" $1
+-		status=$?
+-		;;
+-	*)	echo $USAGE 1>&2
+-		exit 2
+-		;;
+-esac
+-exit $status
+diff --git a/fsr/xfs_fsr.c b/fsr/xfs_fsr.c
+index 3818f02..48629fd 100644
+--- a/fsr/xfs_fsr.c
++++ b/fsr/xfs_fsr.c
+@@ -554,6 +554,8 @@ fsrallfs(char *mtab, int howlong, char *leftofffile)
+ 			fsrprintf(_("could not read %s, starting with %s\n"),
+ 				leftofffile, *fs->dev);
+ 		} else {
++			/* Ensure the buffer we read is null terminated */
++			buf[SMBUFSZ-1] = '\0';
+ 			for (fs = fsbase; fs < fsend; fs++) {
+ 				fsname = fs->dev;
+ 				if ((strncmp(buf,fsname,strlen(fsname)) == 0)
+@@ -1203,14 +1205,20 @@ out:
+  * We already are pretty sure we can and want to
+  * defragment the file.  Create the tmp file, copy
+  * the data (maintaining holes) and call the kernel
+- * extent swap routinte.
++ * extent swap routine.
++ *
++ * Return values:
++ * -1: Some error was encountered
++ *  0: Successfully defragmented the file
++ *  1: No change / No Error
+  */
+ static int
+ packfile(char *fname, char *tname, int fd,
+ 	 xfs_bstat_t *statp, struct fsxattr *fsxp)
+ {
+-	int 		tfd;
++	int 		tfd = -1;
+ 	int		srval;
++	int		retval = -1;	/* Failure is the default */
+ 	int		nextents, extent, cur_nextents, new_nextents;
+ 	unsigned	blksz_dio;
+ 	unsigned	dio_min;
+@@ -1218,7 +1226,7 @@ packfile(char *fname, char *tname, int fd,
+ 	static xfs_swapext_t   sx;
+ 	struct xfs_flock64  space;
+ 	off64_t 	cnt, pos;
+-	void 		*fbuf;
++	void 		*fbuf = NULL;
+ 	int 		ct, wc, wc_b4;
+ 	char		ffname[SMBUFSZ];
+ 	int		ffd = -1;
+@@ -1234,7 +1242,8 @@ packfile(char *fname, char *tname, int fd,
+ 	if (cur_nextents == 1 || cur_nextents <= nextents) {
+ 		if (vflag)
+ 			fsrprintf(_("%s already fully defragmented.\n"), fname);
+-		return 1; /* indicates no change/no error */
++		retval = 1; /* indicates no change/no error */
++		goto out;
+ 	}
+ 
+ 	if (dflag)
+@@ -1246,15 +1255,14 @@ packfile(char *fname, char *tname, int fd,
+ 		if (vflag)
+ 			fsrprintf(_("could not open tmp file: %s: %s\n"),
+ 				   tname, strerror(errno));
+-		return -1;
++		goto out;
+ 	}
+ 	unlink(tname);
+ 
+ 	/* Setup extended attributes */
+ 	if (fsr_setup_attr_fork(fd, tfd, statp) != 0) {
+ 		fsrprintf(_("failed to set ATTR fork on tmp: %s:\n"), tname);
+-		close(tfd);
+-		return -1;
++		goto out;
+ 	}
+ 
+ 	/* Setup extended inode flags, project identifier, etc */
+@@ -1262,15 +1270,13 @@ packfile(char *fname, char *tname, int fd,
+ 		if (ioctl(tfd, XFS_IOC_FSSETXATTR, fsxp) < 0) {
+ 			fsrprintf(_("could not set inode attrs on tmp: %s\n"),
+ 				tname);
+-			close(tfd);
+-			return -1;
++			goto out;
+ 		}
+ 	}
+ 
+ 	if ((ioctl(tfd, XFS_IOC_DIOINFO, &dio)) < 0 ) {
+ 		fsrprintf(_("could not get DirectIO info on tmp: %s\n"), tname);
+-		close(tfd);
+-		return -1;
++		goto out;
+ 	}
+ 
+ 	dio_min = dio.d_miniosz;
+@@ -1292,8 +1298,7 @@ packfile(char *fname, char *tname, int fd,
+ 
+ 	if (!(fbuf = (char *)memalign(dio.d_mem, blksz_dio))) {
+ 		fsrprintf(_("could not allocate buf: %s\n"), tname);
+-		close(tfd);
+-		return -1;
++		goto out;
+ 	}
+ 
+ 	if (nfrags) {
+@@ -1304,9 +1309,7 @@ packfile(char *fname, char *tname, int fd,
+ 		if ((ffd = open(ffname, openopts, 0666)) < 0) {
+ 			fsrprintf(_("could not open fragfile: %s : %s\n"),
+ 				   ffname, strerror(errno));
+-			close(tfd);
+-			free(fbuf);
+-			return -1;
++			goto out;
+ 		}
+ 		unlink(ffname);
+ 	}
+@@ -1322,7 +1325,11 @@ packfile(char *fname, char *tname, int fd,
+ 				fsrprintf(_("could not trunc tmp %s\n"),
+ 					   tname);
+ 			}
+-			lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
++			if (lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
++				fsrprintf(_("could not lseek in tmpfile: %s : %s\n"),
++				   tname, strerror(errno));
++				goto out;
++			}
+ 			continue;
+ 		} else if (outmap[extent].bmv_length == 0) {
+ 			/* to catch holes at the beginning of the file */
+@@ -1336,21 +1343,19 @@ packfile(char *fname, char *tname, int fd,
+ 			if (ioctl(tfd, XFS_IOC_RESVSP64, &space) < 0) {
+ 				fsrprintf(_("could not pre-allocate tmp space:"
+ 					" %s\n"), tname);
+-				close(tfd);
+-				free(fbuf);
+-				return -1;
++				goto out;
++			}
++			if (lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
++				fsrprintf(_("could not lseek in tmpfile: %s : %s\n"),
++				   tname, strerror(errno));
++				goto out;
+ 			}
+-			lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
+ 		}
+ 	} /* end of space allocation loop */
+ 
+ 	if (lseek64(tfd, 0, SEEK_SET)) {
+ 		fsrprintf(_("Couldn't rewind on temporary file\n"));
+-		close(tfd);
+-		if (ffd != -1)
+-			close(ffd);
+-		free(fbuf);
+-		return -1;
++		goto out;
+ 	}
+ 
+ 	/* Check if the temporary file has fewer extents */
+@@ -1360,19 +1365,24 @@ packfile(char *fname, char *tname, int fd,
+ 	if (cur_nextents <= new_nextents) {
+ 		if (vflag)
+ 			fsrprintf(_("No improvement will be made (skipping): %s\n"), fname);
+-		free(fbuf);
+-		close(tfd);
+-		if (ffd != -1)
+-			close(ffd);
+-		return 1; /* no change/no error */
++		retval = 1; /* no change/no error */
++		goto out;
+ 	}
+ 
+ 	/* Loop through block map copying the file. */
+ 	for (extent = 0; extent < nextents; extent++) {
+ 		pos = outmap[extent].bmv_offset;
+ 		if (outmap[extent].bmv_block == -1) {
+-			lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
+-			lseek64(fd, outmap[extent].bmv_length, SEEK_CUR);
++			if (lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
++				fsrprintf(_("could not lseek in tmpfile: %s : %s\n"),
++				   tname, strerror(errno));
++				goto out;
++			}
++			if (lseek64(fd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
++				fsrprintf(_("could not lseek in file: %s : %s\n"),
++				   fname, strerror(errno));
++				goto out;
++			}
+ 			continue;
+ 		} else if (outmap[extent].bmv_length == 0) {
+ 			/* to catch holes at the beginning of the file */
+@@ -1435,11 +1445,7 @@ packfile(char *fname, char *tname, int fd,
+ 							tname);
+ 					}
+ 				}
+-				free(fbuf);
+-				close(tfd);
+-				if (ffd != -1)
+-					close(ffd);
+-				return -1;
++				goto out;
+ 			}
+ 			if (nfrags) {
+ 				/* Do a matching write to the tmp file */
+@@ -1452,12 +1458,16 @@ packfile(char *fname, char *tname, int fd,
+ 			}
+ 		}
+ 	}
+-	ftruncate64(tfd, statp->bs_size);
+-	if (ffd != -1)
+-		close(ffd);
+-	fsync(tfd);
+-
+-	free(fbuf);
++	if (ftruncate64(tfd, statp->bs_size) < 0) {
++		fsrprintf(_("could not truncate tmpfile: %s : %s\n"),
++				fname, strerror(errno));
++		goto out;
++	}
++	if (fsync(tfd) < 0) {
++		fsrprintf(_("could not fsync tmpfile: %s : %s\n"),
++				fname, strerror(errno));
++		goto out;
++	}
+ 
+ 	sx.sx_stat     = *statp; /* struct copy */
+ 	sx.sx_version  = XFS_SX_VERSION;
+@@ -1471,8 +1481,7 @@ packfile(char *fname, char *tname, int fd,
+                 if (vflag)
+                         fsrprintf(_("failed to fchown tmpfile %s: %s\n"),
+                                    tname, strerror(errno));
+-		close(tfd);
+-                return -1;
++		goto out;
+         }
+ 
+ 	/* Swap the extents */
+@@ -1494,8 +1503,7 @@ packfile(char *fname, char *tname, int fd,
+ 			fsrprintf(_("XFS_IOC_SWAPEXT failed: %s: %s\n"),
+ 				  fname, strerror(errno));
+ 		}
+-		close(tfd);
+-		return -1;
++		goto out;
+ 	}
+ 
+ 	/* Report progress */
+@@ -1504,8 +1512,15 @@ packfile(char *fname, char *tname, int fd,
+ 			  cur_nextents, new_nextents,
+ 			  (new_nextents <= nextents ? "DONE" : "    " ),
+ 		          fname);
+-	close(tfd);
+-	return 0;
++	retval = 0;
++
++out:
++	free(fbuf);
++	if (tfd != -1)
++		close(tfd);
++	if (ffd != -1)
++		close(ffd);
++	return retval;
+ }
+ 
+ char *
+diff --git a/growfs/xfs_growfs.c b/growfs/xfs_growfs.c
+index 77da707..8e611b6 100644
+--- a/growfs/xfs_growfs.c
++++ b/growfs/xfs_growfs.c
+@@ -56,12 +56,13 @@ report_info(
+ 	int		projid32bit,
+ 	int		crcs_enabled,
+ 	int		cimode,
+-	int		ftype_enabled)
++	int		ftype_enabled,
++	int		finobt_enabled)
+ {
+ 	printf(_(
+ 	    "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
+ 	    "         =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
+-	    "         =%-22s crc=%u\n"
++	    "         =%-22s crc=%-8u finobt=%u\n"
+ 	    "data     =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
+ 	    "         =%-22s sunit=%-6u swidth=%u blks\n"
+ 	    "naming   =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
+@@ -71,7 +72,7 @@ report_info(
+ 
+ 		mntpoint, geo.inodesize, geo.agcount, geo.agblocks,
+ 		"", geo.sectsize, attrversion, projid32bit,
+-		"", crcs_enabled,
++		"", crcs_enabled, finobt_enabled,
+ 		"", geo.blocksize, (unsigned long long)geo.datablocks,
+ 			geo.imaxpct,
+ 		"", geo.sunit, geo.swidth,
+@@ -123,6 +124,7 @@ main(int argc, char **argv)
+ 	int			projid32bit;
+ 	int			crcs_enabled;
+ 	int			ftype_enabled = 0;
++	int			finobt_enabled;	/* free inode btree */
+ 
+ 	progname = basename(argv[0]);
+ 	setlocale(LC_ALL, "");
+@@ -244,11 +246,12 @@ main(int argc, char **argv)
+ 	projid32bit = geo.flags & XFS_FSOP_GEOM_FLAGS_PROJID32 ? 1 : 0;
+ 	crcs_enabled = geo.flags & XFS_FSOP_GEOM_FLAGS_V5SB ? 1 : 0;
+ 	ftype_enabled = geo.flags & XFS_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0;
++	finobt_enabled = geo.flags & XFS_FSOP_GEOM_FLAGS_FINOBT ? 1 : 0;
+ 	if (nflag) {
+ 		report_info(geo, datadev, isint, logdev, rtdev,
+ 				lazycount, dirversion, logversion,
+ 				attrversion, projid32bit, crcs_enabled, ci,
+-				ftype_enabled);
++				ftype_enabled, finobt_enabled);
+ 		exit(0);
+ 	}
+ 
+@@ -285,7 +288,8 @@ main(int argc, char **argv)
+ 
+ 	report_info(geo, datadev, isint, logdev, rtdev,
+ 			lazycount, dirversion, logversion,
+-			attrversion, projid32bit, crcs_enabled, ci, ftype_enabled);
++			attrversion, projid32bit, crcs_enabled, ci, ftype_enabled,
++			finobt_enabled);
+ 
+ 	ddsize = xi.dsize;
+ 	dlsize = ( xi.logBBsize? xi.logBBsize :
+diff --git a/include/libxfs.h b/include/libxfs.h
+index 9c10957..45a924f 100644
+--- a/include/libxfs.h
++++ b/include/libxfs.h
+@@ -480,7 +480,6 @@ typedef struct xfs_inode_log_item {
+ 	unsigned int		ili_fields;		/* fields to be logged */
+ 	unsigned int		ili_last_fields;	/* fields when flushed*/
+ 	xfs_inode_log_format_t	ili_format;		/* logged structure */
+-	int			ili_lock_flags;
+ } xfs_inode_log_item_t;
+ 
+ typedef struct xfs_buf_log_item {
+@@ -535,9 +534,7 @@ extern xfs_buf_t	*libxfs_trans_getsb (xfs_trans_t *, xfs_mount_t *, int);
+ 
+ extern int	libxfs_trans_iget (xfs_mount_t *, xfs_trans_t *, xfs_ino_t,
+ 				uint, uint, struct xfs_inode **);
+-extern void	libxfs_trans_iput(xfs_trans_t *, struct xfs_inode *, uint);
+ extern void	libxfs_trans_ijoin (xfs_trans_t *, struct xfs_inode *, uint);
+-extern void	libxfs_trans_ihold (xfs_trans_t *, struct xfs_inode *);
+ extern void	libxfs_trans_ijoin_ref(xfs_trans_t *, struct xfs_inode *, int);
+ extern void	libxfs_trans_log_inode (xfs_trans_t *, struct xfs_inode *,
+ 				uint);
+@@ -656,7 +653,9 @@ extern int	libxfs_iflush_int (xfs_inode_t *, xfs_buf_t *);
+ /* Inode Cache Interfaces */
+ extern int	libxfs_iget (xfs_mount_t *, xfs_trans_t *, xfs_ino_t,
+ 				uint, xfs_inode_t **, xfs_daddr_t);
+-extern void	libxfs_iput (xfs_inode_t *, uint);
++extern void	libxfs_iput (xfs_inode_t *);
++
++#define IRELE(ip) libxfs_iput(ip)
+ 
+ /* Shared utility routines */
+ extern unsigned int	libxfs_log2_roundup(unsigned int i);
+@@ -760,6 +759,7 @@ bool xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
+ /* xfs_sb.h */
+ #define libxfs_mod_sb			xfs_mod_sb
+ #define libxfs_sb_from_disk		xfs_sb_from_disk
++#define libxfs_sb_quota_from_disk	xfs_sb_quota_from_disk
+ #define libxfs_sb_to_disk		xfs_sb_to_disk
+ 
+ /* xfs_symlink.h */
+diff --git a/include/xfs_ag.h b/include/xfs_ag.h
+index 0fdd410..2531658 100644
+--- a/include/xfs_ag.h
++++ b/include/xfs_ag.h
+@@ -166,24 +166,30 @@ typedef struct xfs_agi {
+ 	__be32		agi_pad32;
+ 	__be64		agi_lsn;	/* last write sequence */
+ 
++	__be32		agi_free_root; /* root of the free inode btree */
++	__be32		agi_free_level;/* levels in free inode btree */
++
+ 	/* structure must be padded to 64 bit alignment */
+ } xfs_agi_t;
+ 
+ #define XFS_AGI_CRC_OFF		offsetof(struct xfs_agi, agi_crc)
+ 
+-#define	XFS_AGI_MAGICNUM	0x00000001
+-#define	XFS_AGI_VERSIONNUM	0x00000002
+-#define	XFS_AGI_SEQNO		0x00000004
+-#define	XFS_AGI_LENGTH		0x00000008
+-#define	XFS_AGI_COUNT		0x00000010
+-#define	XFS_AGI_ROOT		0x00000020
+-#define	XFS_AGI_LEVEL		0x00000040
+-#define	XFS_AGI_FREECOUNT	0x00000080
+-#define	XFS_AGI_NEWINO		0x00000100
+-#define	XFS_AGI_DIRINO		0x00000200
+-#define	XFS_AGI_UNLINKED	0x00000400
+-#define	XFS_AGI_NUM_BITS	11
+-#define	XFS_AGI_ALL_BITS	((1 << XFS_AGI_NUM_BITS) - 1)
++#define	XFS_AGI_MAGICNUM	(1 << 0)
++#define	XFS_AGI_VERSIONNUM	(1 << 1)
++#define	XFS_AGI_SEQNO		(1 << 2)
++#define	XFS_AGI_LENGTH		(1 << 3)
++#define	XFS_AGI_COUNT		(1 << 4)
++#define	XFS_AGI_ROOT		(1 << 5)
++#define	XFS_AGI_LEVEL		(1 << 6)
++#define	XFS_AGI_FREECOUNT	(1 << 7)
++#define	XFS_AGI_NEWINO		(1 << 8)
++#define	XFS_AGI_DIRINO		(1 << 9)
++#define	XFS_AGI_UNLINKED	(1 << 10)
++#define	XFS_AGI_NUM_BITS_R1	11	/* end of the 1st agi logging region */
++#define	XFS_AGI_ALL_BITS_R1	((1 << XFS_AGI_NUM_BITS_R1) - 1)
++#define	XFS_AGI_FREE_ROOT	(1 << 11)
++#define	XFS_AGI_FREE_LEVEL	(1 << 12)
++#define	XFS_AGI_NUM_BITS_R2	13
+ 
+ /* disk block (xfs_daddr_t) in the AG */
+ #define XFS_AGI_DADDR(mp)	((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
+diff --git a/include/xfs_btree.h b/include/xfs_btree.h
+index 6afe0b2..2590d40 100644
+--- a/include/xfs_btree.h
++++ b/include/xfs_btree.h
+@@ -37,6 +37,7 @@ extern kmem_zone_t	*xfs_btree_cur_zone;
+ #define	XFS_BTNUM_CNT	((xfs_btnum_t)XFS_BTNUM_CNTi)
+ #define	XFS_BTNUM_BMAP	((xfs_btnum_t)XFS_BTNUM_BMAPi)
+ #define	XFS_BTNUM_INO	((xfs_btnum_t)XFS_BTNUM_INOi)
++#define	XFS_BTNUM_FINO	((xfs_btnum_t)XFS_BTNUM_FINOi)
+ 
+ /*
+  * For logging record fields.
+@@ -67,6 +68,7 @@ do {    \
+ 	case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break;	\
+ 	case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break;	\
+ 	case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break;	\
++	case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break;	\
+ 	case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;	\
+ 	}       \
+ } while (0)
+@@ -80,6 +82,7 @@ do {    \
+ 	case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
+ 	case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
+ 	case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
++	case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \
+ 	case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;	\
+ 	}       \
+ } while (0)
+diff --git a/include/xfs_format.h b/include/xfs_format.h
+index 77f6b8b..758052f 100644
+--- a/include/xfs_format.h
++++ b/include/xfs_format.h
+@@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t;
+  */
+ #define	XFS_IBT_MAGIC		0x49414254	/* 'IABT' */
+ #define	XFS_IBT_CRC_MAGIC	0x49414233	/* 'IAB3' */
++#define	XFS_FIBT_MAGIC		0x46494254	/* 'FIBT' */
++#define	XFS_FIBT_CRC_MAGIC	0x46494233	/* 'FIB3' */
+ 
+ typedef	__uint64_t	xfs_inofree_t;
+ #define	XFS_INODES_PER_CHUNK		(NBBY * sizeof(xfs_inofree_t))
+@@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t;
+  * block numbers in the AG.
+  */
+ #define	XFS_IBT_BLOCK(mp)		((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1))
+-#define	XFS_PREALLOC_BLOCKS(mp)		((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
++#define	XFS_FIBT_BLOCK(mp)		((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
++
++/*
++ * The first data block of an AG depends on whether the filesystem was formatted
++ * with the finobt feature. If so, account for the finobt reserved root btree
++ * block.
++ */
++#define XFS_PREALLOC_BLOCKS(mp) \
++	(xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
++	 XFS_FIBT_BLOCK(mp) + 1 : \
++	 XFS_IBT_BLOCK(mp) + 1)
+ 
+ 
+ 
+diff --git a/include/xfs_fs.h b/include/xfs_fs.h
+index 554fd66..59c40fc 100644
+--- a/include/xfs_fs.h
++++ b/include/xfs_fs.h
+@@ -238,6 +238,7 @@ typedef struct xfs_fsop_resblks {
+ #define XFS_FSOP_GEOM_FLAGS_LAZYSB	0x4000	/* lazy superblock counters */
+ #define XFS_FSOP_GEOM_FLAGS_V5SB	0x8000	/* version 5 superblock */
+ #define XFS_FSOP_GEOM_FLAGS_FTYPE	0x10000	/* inode directory types */
++#define XFS_FSOP_GEOM_FLAGS_FINOBT	0x20000	/* free inode btree */
+ 
+ 
+ /*
+diff --git a/include/xfs_ialloc.h b/include/xfs_ialloc.h
+index a8f76a5..c8ac0a4 100644
+--- a/include/xfs_ialloc.h
++++ b/include/xfs_ialloc.h
+@@ -89,7 +89,7 @@ xfs_difree(
+ 	struct xfs_trans *tp,		/* transaction pointer */
+ 	xfs_ino_t	inode,		/* inode to be freed */
+ 	struct xfs_bmap_free *flist,	/* extents to free */
+-	int		*delete,	/* set if inode cluster was deleted */
++	int		*deleted,	/* set if inode cluster was deleted */
+ 	xfs_ino_t	*first_ino);	/* first inode in deleted cluster */
+ 
+ /*
+diff --git a/include/xfs_ialloc_btree.h b/include/xfs_ialloc_btree.h
+index f38b220..d7ebea7 100644
+--- a/include/xfs_ialloc_btree.h
++++ b/include/xfs_ialloc_btree.h
+@@ -58,7 +58,8 @@ struct xfs_mount;
+ 		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
+ 
+ extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
+-		struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t);
++		struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
++		xfs_btnum_t);
+ extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
+ 
+ #endif	/* __XFS_IALLOC_BTREE_H__ */
+diff --git a/include/xfs_sb.h b/include/xfs_sb.h
+index f7b2fe7..950d1ea 100644
+--- a/include/xfs_sb.h
++++ b/include/xfs_sb.h
+@@ -587,7 +587,9 @@ xfs_sb_has_compat_feature(
+ 	return (sbp->sb_features_compat & feature) != 0;
+ }
+ 
+-#define XFS_SB_FEAT_RO_COMPAT_ALL 0
++#define XFS_SB_FEAT_RO_COMPAT_FINOBT   (1 << 0)		/* free inode btree */
++#define XFS_SB_FEAT_RO_COMPAT_ALL \
++		(XFS_SB_FEAT_RO_COMPAT_FINOBT)
+ #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN	~XFS_SB_FEAT_RO_COMPAT_ALL
+ static inline bool
+ xfs_sb_has_ro_compat_feature(
+@@ -641,6 +643,12 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp)
+ 		 (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE));
+ }
+ 
++static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
++{
++	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
++		(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT);
++}
++
+ /*
+  * end of superblock version macros
+  */
+diff --git a/include/xfs_trans_space.h b/include/xfs_trans_space.h
+index 7d2c920..a7d1721 100644
+--- a/include/xfs_trans_space.h
++++ b/include/xfs_trans_space.h
+@@ -47,7 +47,9 @@
+ #define	XFS_DIRREMOVE_SPACE_RES(mp)	\
+ 	XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
+ #define	XFS_IALLOC_SPACE_RES(mp)	\
+-	(XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels - 1)
++	(XFS_IALLOC_BLOCKS(mp) + \
++	 (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
++	  ((mp)->m_in_maxlevels - 1)))
+ 
+ /*
+  * Space reservation values for various transactions.
+@@ -82,5 +84,8 @@
+ 	(XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
+ #define	XFS_SYMLINK_SPACE_RES(mp,nl,b)	\
+ 	(XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
++#define XFS_IFREE_SPACE_RES(mp)		\
++	(xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
++
+ 
+ #endif	/* __XFS_TRANS_SPACE_H__ */
+diff --git a/include/xfs_types.h b/include/xfs_types.h
+index 82bbc34..65c6e66 100644
+--- a/include/xfs_types.h
++++ b/include/xfs_types.h
+@@ -134,7 +134,7 @@ typedef enum {
+ 
+ typedef enum {
+ 	XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+-	XFS_BTNUM_MAX
++	XFS_BTNUM_FINOi, XFS_BTNUM_MAX
+ } xfs_btnum_t;
+ 
+ struct xfs_name {
+diff --git a/libxfs/init.c b/libxfs/init.c
+index 0924948..06458e5 100644
+--- a/libxfs/init.c
++++ b/libxfs/init.c
+@@ -778,9 +778,9 @@ void
+ libxfs_rtmount_destroy(xfs_mount_t *mp)
+ {
+ 	if (mp->m_rsumip)
+-		libxfs_iput(mp->m_rsumip, 0);
++		IRELE(mp->m_rsumip);
+ 	if (mp->m_rbmip)
+-		libxfs_iput(mp->m_rbmip, 0);
++		IRELE(mp->m_rbmip);
+ 	mp->m_rsumip = mp->m_rbmip = NULL;
+ }
+ 
+diff --git a/libxfs/linux.c b/libxfs/linux.c
+index 2e07d54..8d1a117 100644
+--- a/libxfs/linux.c
++++ b/libxfs/linux.c
+@@ -141,10 +141,20 @@ platform_findsizes(char *path, int fd, long long *sz, int *bsz)
+ 		exit(1);
+ 	}
+ 	if ((st.st_mode & S_IFMT) == S_IFREG) {
++		struct xfs_fsop_geom_v1 geom = { 0 };
++
+ 		*sz = (long long)(st.st_size >> 9);
+-		*bsz = BBSIZE;
+-		if (BBSIZE > max_block_alignment)
+-			max_block_alignment = BBSIZE;
++		if (ioctl(fd, XFS_IOC_FSGEOMETRY_V1, &geom) < 0) {
++			/*
++			 * fall back to BBSIZE; mkfs might fail if there's a
++			 * size mismatch between the image & the host fs...
++			 */
++			*bsz = BBSIZE;
++		} else
++			*bsz = geom.sectsize;
++
++		if (*bsz > max_block_alignment)
++			max_block_alignment = *bsz;
+ 		return;
+ 	}
+ 
+diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
+index 57c12c1..0294c98 100644
+--- a/libxfs/rdwr.c
++++ b/libxfs/rdwr.c
+@@ -19,6 +19,37 @@
+ #include <xfs/libxfs.h>
+ #include "init.h"
+ 
++/*
++ * Important design/architecture note:
++ *
++ * The userspace code that uses the buffer cache is much less constrained than
++ * the kernel code. The userspace code is pretty nasty in places, especially
++ * when it comes to buffer error handling.  Very little of the userspace code
++ * outside libxfs clears bp->b_error - very little code even checks it - so the
++ * libxfs code is tripping on stale errors left by the userspace code.
++ *
++ * We can't clear errors or zero buffer contents in libxfs_getbuf-* like we do
++ * in the kernel, because those functions are used by the libxfs_readbuf_*
++ * functions and hence need to leave the buffers unchanged on cache hits. This
++ * is actually the only way to gather a write error from a libxfs_writebuf()
++ * call - you need to get the buffer again so you can check bp->b_error field -
++ * assuming that the buffer is still in the cache when you check, that is.
++ *
++ * This is very different to the kernel code which does not release buffers on a
++ * write so we can wait on IO and check errors. The kernel buffer cache also
++ * guarantees a buffer of a known initial state from xfs_buf_get() even on a
++ * cache hit.
++ *
++ * IOWs, userspace is behaving quite differently to the kernel and as a result
++ * it leaks errors from reads, invalidations and writes through
++ * libxfs_getbuf/libxfs_readbuf.
++ *
++ * The result of this is that until the userspace code outside libxfs is cleaned
++ * up, functions that release buffers from userspace control (i.e
++ * libxfs_writebuf/libxfs_putbuf) need to zero bp->b_error to prevent
++ * propagation of stale errors into future buffer operations.
++ */
++
+ #define BDSTRAT_SIZE	(256 * 1024)
+ 
+ #define IO_BCOMPARE_CHECK
+@@ -632,6 +663,12 @@ libxfs_putbuf(xfs_buf_t *bp)
+ 			pthread_mutex_unlock(&bp->b_lock);
+ 		}
+ 	}
++	/*
++	 * ensure that any errors on this use of the buffer don't carry
++	 * over to the next user.
++	 */
++	bp->b_error = 0;
++
+ 	cache_node_put(libxfs_bcache, (struct cache_node *)bp);
+ }
+ 
+@@ -907,10 +944,10 @@ libxfs_writebufr(xfs_buf_t *bp)
+ 	}
+ 
+ #ifdef IO_DEBUG
+-	printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p\n",
++	printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p, error %d\n",
+ 			pthread_self(), __FUNCTION__, bp->b_bcount,
+ 			(long long)LIBXFS_BBTOOFF64(bp->b_bn),
+-			(long long)bp->b_bn, bp);
++			(long long)bp->b_bn, bp, error);
+ #endif
+ 	if (!error) {
+ 		bp->b_flags |= LIBXFS_B_UPTODATE;
+@@ -928,6 +965,7 @@ libxfs_writebuf_int(xfs_buf_t *bp, int flags)
+ 	 * subsequent reads after this write from seeing stale errors.
+ 	 */
+ 	bp->b_error = 0;
++	bp->b_flags &= ~LIBXFS_B_STALE;
+ 	bp->b_flags |= (LIBXFS_B_DIRTY | flags);
+ 	return 0;
+ }
+@@ -946,6 +984,7 @@ libxfs_writebuf(xfs_buf_t *bp, int flags)
+ 	 * subsequent reads after this write from seeing stale errors.
+ 	 */
+ 	bp->b_error = 0;
++	bp->b_flags &= ~LIBXFS_B_STALE;
+ 	bp->b_flags |= (LIBXFS_B_DIRTY | flags);
+ 	libxfs_putbuf(bp);
+ 	return 0;
+@@ -1103,7 +1142,7 @@ libxfs_idestroy(xfs_inode_t *ip)
+ }
+ 
+ void
+-libxfs_iput(xfs_inode_t *ip, uint lock_flags)
++libxfs_iput(xfs_inode_t *ip)
+ {
+ 	if (ip->i_itemp)
+ 		kmem_zone_free(xfs_ili_zone, ip->i_itemp);
+diff --git a/libxfs/trans.c b/libxfs/trans.c
+index c443863..13d21b2 100644
+--- a/libxfs/trans.c
++++ b/libxfs/trans.c
+@@ -110,7 +110,7 @@ libxfs_trans_roll(
+ 	/*
+ 	 * Commit the current transaction.
+ 	 * If this commit failed, then it'd just unlock those items that
+-	 * are not marked ihold. That also means that a filesystem shutdown
++	 * are marked to be released. That also means that a filesystem shutdown
+ 	 * is in progress. The caller takes the responsibility to cancel
+ 	 * the duplicate transaction that gets returned.
+ 	 */
+@@ -248,27 +248,6 @@ libxfs_trans_iget(
+ }
+ 
+ void
+-libxfs_trans_iput(
+-	xfs_trans_t		*tp,
+-	xfs_inode_t		*ip,
+-	uint			lock_flags)
+-{
+-	xfs_inode_log_item_t	*iip;
+-
+-	if (tp == NULL) {
+-		libxfs_iput(ip, lock_flags);
+-		return;
+-	}
+-
+-	ASSERT(ip->i_transp == tp);
+-	iip = ip->i_itemp;
+-	ASSERT(iip != NULL);
+-	xfs_trans_del_item(&iip->ili_item);
+-
+-	libxfs_iput(ip, lock_flags);
+-}
+-
+-void
+ libxfs_trans_ijoin(
+ 	xfs_trans_t		*tp,
+ 	xfs_inode_t		*ip,
+@@ -301,7 +280,6 @@ libxfs_trans_ijoin_ref(
+ 	ASSERT(ip->i_itemp != NULL);
+ 
+ 	xfs_trans_ijoin(tp, ip, lock_flags);
+-	ip->i_itemp->ili_lock_flags = lock_flags;
+ 
+ #ifdef XACT_DEBUG
+ 	fprintf(stderr, "ijoin_ref'd inode %llu, transaction %p\n", ip->i_ino, tp);
+@@ -309,21 +287,6 @@ libxfs_trans_ijoin_ref(
+ }
+ 
+ void
+-libxfs_trans_ihold(
+-	xfs_trans_t		*tp,
+-	xfs_inode_t		*ip)
+-{
+-	ASSERT(ip->i_transp == tp);
+-	ASSERT(ip->i_itemp != NULL);
+-
+-	ip->i_itemp->ili_lock_flags = 1;
+-
+-#ifdef XACT_DEBUG
+-	fprintf(stderr, "ihold'd inode %llu, transaction %p\n", ip->i_ino, tp);
+-#endif
+-}
+-
+-void
+ libxfs_trans_inode_alloc_buf(
+ 	xfs_trans_t		*tp,
+ 	xfs_buf_t		*bp)
+@@ -702,7 +665,7 @@ inode_item_done(
+ 	if (!(iip->ili_fields & XFS_ILOG_ALL)) {
+ 		ip->i_transp = NULL;	/* disassociate from transaction */
+ 		iip->ili_flags = 0;	/* reset all flags */
+-		goto ili_done;
++		return;
+ 	}
+ 
+ 	/*
+@@ -712,7 +675,7 @@ inode_item_done(
+ 	if (error) {
+ 		fprintf(stderr, _("%s: warning - imap_to_bp failed (%d)\n"),
+ 			progname, error);
+-		goto ili_done;
++		return;
+ 	}
+ 
+ 	XFS_BUF_SET_FSPRIVATE(bp, iip);
+@@ -720,7 +683,7 @@ inode_item_done(
+ 	if (error) {
+ 		fprintf(stderr, _("%s: warning - iflush_int failed (%d)\n"),
+ 			progname, error);
+-		goto ili_done;
++		return;
+ 	}
+ 
+ 	ip->i_transp = NULL;	/* disassociate from transaction */
+@@ -728,16 +691,9 @@ inode_item_done(
+ 	XFS_BUF_SET_FSPRIVATE2(bp, NULL);	/* remove xact ptr */
+ 	libxfs_writebuf(bp, 0);
+ #ifdef XACT_DEBUG
+-	fprintf(stderr, "flushing dirty inode %llu, buffer %p (hold=%u)\n",
+-			ip->i_ino, bp, iip->ili_lock_flags);
++	fprintf(stderr, "flushing dirty inode %llu, buffer %p\n",
++			ip->i_ino, bp);
+ #endif
+-ili_done:
+-	if (iip->ili_lock_flags) {
+-		iip->ili_lock_flags = 0;
+-		return;
+-	}
+-	/* free the inode */
+-	libxfs_iput(ip, 0);
+ }
+ 
+ static void
+@@ -818,10 +774,6 @@ inode_item_unlock(
+ 	ip->i_transp = NULL;
+ 
+ 	iip->ili_flags = 0;
+-	if (!iip->ili_lock_flags)
+-		libxfs_iput(ip, 0);
+-	else
+-		iip->ili_lock_flags = 0;
+ }
+ 
+ /*
+diff --git a/libxfs/util.c b/libxfs/util.c
+index 4c40324..9504e33 100644
+--- a/libxfs/util.c
++++ b/libxfs/util.c
+@@ -595,7 +595,6 @@ libxfs_alloc_file_space(
+ 			break;
+ 		}
+ 		xfs_trans_ijoin(tp, ip, 0);
+-		xfs_trans_ihold(tp, ip);
+ 
+ 		xfs_bmap_init(&free_list, &firstfsb);
+ 		error = xfs_bmapi_write(tp, ip, startoffset_fsb, allocatesize_fsb,
+diff --git a/libxfs/xfs.h b/libxfs/xfs.h
+index 5a21590..30a316d 100644
+--- a/libxfs/xfs.h
++++ b/libxfs/xfs.h
+@@ -292,7 +292,6 @@ roundup_64(__uint64_t x, __uint32_t y)
+ #define xfs_trans_get_buf		libxfs_trans_get_buf
+ #define xfs_trans_getsb			libxfs_trans_getsb
+ #define xfs_trans_iget			libxfs_trans_iget
+-#define xfs_trans_ihold			libxfs_trans_ihold
+ #define xfs_trans_ijoin			libxfs_trans_ijoin
+ #define xfs_trans_ijoin_ref		libxfs_trans_ijoin_ref
+ #define xfs_trans_init			libxfs_trans_init
+diff --git a/libxfs/xfs_attr_remote.c b/libxfs/xfs_attr_remote.c
+index 5cf5c73..08b983b 100644
+--- a/libxfs/xfs_attr_remote.c
++++ b/libxfs/xfs_attr_remote.c
+@@ -85,7 +85,7 @@ xfs_attr3_rmt_verify(
+ 	if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
+ 		return false;
+ 	if (be32_to_cpu(rmt->rm_offset) +
+-				be32_to_cpu(rmt->rm_bytes) >= XATTR_SIZE_MAX)
++				be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX)
+ 		return false;
+ 	if (rmt->rm_owner == 0)
+ 		return false;
+diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
+index 9be4abd..cc823f5 100644
+--- a/libxfs/xfs_btree.c
++++ b/libxfs/xfs_btree.c
+@@ -27,9 +27,10 @@ kmem_zone_t	*xfs_btree_cur_zone;
+  * Btree magic numbers.
+  */
+ static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
+-	{ XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC },
++	{ XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
++	  XFS_FIBT_MAGIC },
+ 	{ XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
+-	  XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC }
++	  XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC }
+ };
+ #define xfs_btree_magic(cur) \
+ 	xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
+@@ -1099,6 +1100,7 @@ xfs_btree_set_refs(
+ 		xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF);
+ 		break;
+ 	case XFS_BTNUM_INO:
++	case XFS_BTNUM_FINO:
+ 		xfs_buf_set_ref(bp, XFS_INO_BTREE_REF);
+ 		break;
+ 	case XFS_BTNUM_BMAP:
+diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
+index b70454e..b731b54 100644
+--- a/libxfs/xfs_da_btree.c
++++ b/libxfs/xfs_da_btree.c
+@@ -2582,7 +2582,8 @@ xfs_da_get_buf(
+ 				    mapp, nmap, 0);
+ 	error = bp ? bp->b_error : XFS_ERROR(EIO);
+ 	if (error) {
+-		xfs_trans_brelse(trans, bp);
++		if (bp)
++			xfs_trans_brelse(trans, bp);
+ 		goto out_free;
+ 	}
+ 
+diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
+index c19d84a..5462c54 100644
+--- a/libxfs/xfs_ialloc.c
++++ b/libxfs/xfs_ialloc.c
+@@ -88,6 +88,66 @@ xfs_inobt_get_rec(
+ }
+ 
+ /*
++ * Insert a single inobt record. Cursor must already point to desired location.
++ */
++STATIC int
++xfs_inobt_insert_rec(
++	struct xfs_btree_cur	*cur,
++	__int32_t		freecount,
++	xfs_inofree_t		free,
++	int			*stat)
++{
++	cur->bc_rec.i.ir_freecount = freecount;
++	cur->bc_rec.i.ir_free = free;
++	return xfs_btree_insert(cur, stat);
++}
++
++/*
++ * Insert records describing a newly allocated inode chunk into the inobt.
++ */
++STATIC int
++xfs_inobt_insert(
++	struct xfs_mount	*mp,
++	struct xfs_trans	*tp,
++	struct xfs_buf		*agbp,
++	xfs_agino_t		newino,
++	xfs_agino_t		newlen,
++	xfs_btnum_t		btnum)
++{
++	struct xfs_btree_cur	*cur;
++	struct xfs_agi		*agi = XFS_BUF_TO_AGI(agbp);
++	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
++	xfs_agino_t		thisino;
++	int			i;
++	int			error;
++
++	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
++
++	for (thisino = newino;
++	     thisino < newino + newlen;
++	     thisino += XFS_INODES_PER_CHUNK) {
++		error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i);
++		if (error) {
++			xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
++			return error;
++		}
++		ASSERT(i == 0);
++
++		error = xfs_inobt_insert_rec(cur, XFS_INODES_PER_CHUNK,
++					     XFS_INOBT_ALL_FREE, &i);
++		if (error) {
++			xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
++			return error;
++		}
++		ASSERT(i == 1);
++	}
++
++	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++
++	return 0;
++}
++
++/*
+  * Verify that the number of free inodes in the AGI is correct.
+  */
+ #ifdef DEBUG
+@@ -286,13 +346,10 @@ xfs_ialloc_ag_alloc(
+ {
+ 	xfs_agi_t	*agi;		/* allocation group header */
+ 	xfs_alloc_arg_t	args;		/* allocation argument structure */
+-	xfs_btree_cur_t	*cur;		/* inode btree cursor */
+ 	xfs_agnumber_t	agno;
+ 	int		error;
+-	int		i;
+ 	xfs_agino_t	newino;		/* new first inode's number */
+ 	xfs_agino_t	newlen;		/* new number of inodes */
+-	xfs_agino_t	thisino;	/* current inode number, for loop */
+ 	int		isaligned = 0;	/* inode allocation at stripe unit */
+ 					/* boundary */
+ 	struct xfs_perag *pag;
+@@ -430,29 +487,19 @@ xfs_ialloc_ag_alloc(
+ 	agi->agi_newino = cpu_to_be32(newino);
+ 
+ 	/*
+-	 * Insert records describing the new inode chunk into the btree.
++	 * Insert records describing the new inode chunk into the btrees.
+ 	 */
+-	cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno);
+-	for (thisino = newino;
+-	     thisino < newino + newlen;
+-	     thisino += XFS_INODES_PER_CHUNK) {
+-		cur->bc_rec.i.ir_startino = thisino;
+-		cur->bc_rec.i.ir_freecount = XFS_INODES_PER_CHUNK;
+-		cur->bc_rec.i.ir_free = XFS_INOBT_ALL_FREE;
+-		error = xfs_btree_lookup(cur, XFS_LOOKUP_EQ, &i);
+-		if (error) {
+-			xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+-			return error;
+-		}
+-		ASSERT(i == 0);
+-		error = xfs_btree_insert(cur, &i);
+-		if (error) {
+-			xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
++	error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
++				 XFS_BTNUM_INO);
++	if (error)
++		return error;
++
++	if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
++		error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
++					 XFS_BTNUM_FINO);
++		if (error)
+ 			return error;
+-		}
+-		ASSERT(i == 1);
+ 	}
+-	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+ 	/*
+ 	 * Log allocation group header fields
+ 	 */
+@@ -652,7 +699,7 @@ xfs_ialloc_get_rec(
+  * available.
+  */
+ STATIC int
+-xfs_dialloc_ag(
++xfs_dialloc_ag_slow(
+ 	struct xfs_trans	*tp,
+ 	struct xfs_buf		*agbp,
+ 	xfs_ino_t		parent,
+@@ -678,7 +725,7 @@ xfs_dialloc_ag(
+ 	ASSERT(pag->pagi_freecount > 0);
+ 
+  restart_pagno:
+-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
++	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+ 	/*
+ 	 * If pagino is 0 (this is the root inode allocation) use newino.
+ 	 * This must work because we've just allocated some.
+@@ -910,6 +957,215 @@ error0:
+ 	return error;
+ }
+ 
++STATIC int
++xfs_dialloc_ag(
++	struct xfs_trans	*tp,
++	struct xfs_buf		*agbp,
++	xfs_ino_t		parent,
++	xfs_ino_t		*inop)
++{
++	struct xfs_mount		*mp = tp->t_mountp;
++	struct xfs_agi			*agi = XFS_BUF_TO_AGI(agbp);
++	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
++	xfs_agnumber_t			pagno = XFS_INO_TO_AGNO(mp, parent);
++	xfs_agino_t			pagino = XFS_INO_TO_AGINO(mp, parent);
++	struct xfs_perag		*pag;
++	struct xfs_btree_cur		*cur;
++	struct xfs_btree_cur		*tcur;
++	struct xfs_inobt_rec_incore	rec;
++	struct xfs_inobt_rec_incore	trec;
++	xfs_ino_t			ino;
++	int				error;
++	int				offset;
++	int				i, j;
++
++	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
++		return xfs_dialloc_ag_slow(tp, agbp, parent, inop);
++
++	pag = xfs_perag_get(mp, agno);
++
++	/*
++	 * If pagino is 0 (this is the root inode allocation) use newino.
++	 * This must work because we've just allocated some.
++	 */
++	if (!pagino)
++		pagino = be32_to_cpu(agi->agi_newino);
++
++	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
++
++	error = xfs_check_agi_freecount(cur, agi);
++	if (error)
++		goto error_cur;
++
++	if (agno == pagno) {
++		/*
++		 * We're in the same AG as the parent inode so allocate the
++		 * closest inode to the parent.
++		 */
++		error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i);
++		if (error)
++			goto error_cur;
++		if (i == 1) {
++			error = xfs_inobt_get_rec(cur, &rec, &i);
++			if (error)
++				goto error_cur;
++			XFS_WANT_CORRUPTED_GOTO(i == 1, error_cur);
++
++			/*
++			 * See if we've landed in the parent inode record. The
++			 * finobt only tracks chunks with at least one free
++			 * inode, so record existence is enough.
++			 */
++			if (pagino >= rec.ir_startino &&
++			    pagino < (rec.ir_startino + XFS_INODES_PER_CHUNK))
++				goto alloc_inode;
++		}
++
++		error = xfs_btree_dup_cursor(cur, &tcur);
++		if (error) 
++			goto error_cur;
++
++		error = xfs_inobt_lookup(tcur, pagino, XFS_LOOKUP_GE, &j);
++		if (error)
++			goto error_tcur;
++		if (j == 1) {
++			error = xfs_inobt_get_rec(tcur, &trec, &j);
++			if (error)
++				goto error_tcur;
++			XFS_WANT_CORRUPTED_GOTO(j == 1, error_tcur);
++		}
++
++		if (i == 1 && j == 1) {
++			if ((pagino - rec.ir_startino + XFS_INODES_PER_CHUNK - 1) >
++			    (trec.ir_startino - pagino)) {
++				rec = trec;
++				xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++				cur = tcur;
++			} else {
++				xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
++			}
++		} else if (j == 1) {
++			rec = trec;
++			xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++			cur = tcur;
++		} else {
++			xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
++		}
++	} else {
++		/*
++		 * Different AG from the parent inode. Check the record for the
++		 * most recently allocated inode.
++		 */
++		if (agi->agi_newino != cpu_to_be32(NULLAGINO)) {
++			error = xfs_inobt_lookup(cur, agi->agi_newino,
++						 XFS_LOOKUP_EQ, &i);
++			if (error)
++				goto error_cur;
++			if (i == 1) {
++				error = xfs_inobt_get_rec(cur, &rec, &i);
++				if (error)
++					goto error_cur;
++				XFS_WANT_CORRUPTED_GOTO(i == 1, error_cur);
++				goto alloc_inode;
++			}
++		}
++
++		/*
++		 * Allocate the first inode available in the AG.
++		 */
++		error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
++		if (error)
++			goto error_cur;
++		XFS_WANT_CORRUPTED_GOTO(i == 1, error_cur);
++
++		error = xfs_inobt_get_rec(cur, &rec, &i);
++		if (error)
++			goto error_cur;
++		XFS_WANT_CORRUPTED_GOTO(i == 1, error_cur);
++	}
++
++alloc_inode:
++	offset = xfs_lowbit64(rec.ir_free);
++	ASSERT(offset >= 0);
++	ASSERT(offset < XFS_INODES_PER_CHUNK);
++	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
++				   XFS_INODES_PER_CHUNK) == 0);
++	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
++
++	/*
++	 * Modify or remove the finobt record.
++	 */
++	rec.ir_free &= ~XFS_INOBT_MASK(offset);
++	rec.ir_freecount--;
++	if (rec.ir_freecount) 
++		error = xfs_inobt_update(cur, &rec);
++	else
++		error = xfs_btree_delete(cur, &i);
++	if (error)
++		goto error_cur;
++
++	/*
++	 * Lookup and modify the equivalent record in the inobt.
++	 */
++	tcur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
++
++	error = xfs_check_agi_freecount(tcur, agi);
++	if (error)
++		goto error_tcur;
++
++	error = xfs_inobt_lookup(tcur, rec.ir_startino, XFS_LOOKUP_EQ, &i);
++	if (error)
++		goto error_tcur;
++	XFS_WANT_CORRUPTED_GOTO(i == 1, error_tcur);
++
++	error = xfs_inobt_get_rec(tcur, &trec, &i);
++	if (error)
++		goto error_tcur;
++	XFS_WANT_CORRUPTED_GOTO(i == 1, error_tcur);
++	ASSERT((XFS_AGINO_TO_OFFSET(mp, trec.ir_startino) %
++				   XFS_INODES_PER_CHUNK) == 0);
++
++	trec.ir_free &= ~XFS_INOBT_MASK(offset);
++	trec.ir_freecount--;
++
++	XFS_WANT_CORRUPTED_GOTO((rec.ir_free == trec.ir_free) &&
++				(rec.ir_freecount == trec.ir_freecount),
++				error_tcur);
++
++	error = xfs_inobt_update(tcur, &trec);
++	if (error)
++		goto error_tcur;
++
++	/*
++	 * Update the perag and superblock.
++	 */
++	be32_add_cpu(&agi->agi_freecount, -1);
++	xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
++	pag->pagi_freecount--;
++
++	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
++
++	error = xfs_check_agi_freecount(tcur, agi);
++	if (error)
++		goto error_tcur;
++	error = xfs_check_agi_freecount(cur, agi);
++	if (error)
++		goto error_tcur;
++
++	xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
++	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++	xfs_perag_put(pag);
++	*inop = ino;
++	return 0;
++
++error_tcur:
++	xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
++error_cur:
++	xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
++	xfs_perag_put(pag);
++	return error;
++}
++
+ /*
+  * Allocate an inode on disk.
+  *
+@@ -1069,78 +1325,34 @@ out_error:
+ 	return XFS_ERROR(error);
+ }
+ 
+-/*
+- * Free disk inode.  Carefully avoids touching the incore inode, all
+- * manipulations incore are the caller's responsibility.
+- * The on-disk inode is not changed by this operation, only the
+- * btree (free inode mask) is changed.
+- */
+-int
+-xfs_difree(
+-	xfs_trans_t	*tp,		/* transaction pointer */
+-	xfs_ino_t	inode,		/* inode to be freed */
+-	xfs_bmap_free_t	*flist,		/* extents to free */
+-	int		*delete,	/* set if inode cluster was deleted */
+-	xfs_ino_t	*first_ino)	/* first inode in deleted cluster */
++STATIC int
++xfs_difree_inobt(
++	struct xfs_mount		*mp,
++	struct xfs_trans		*tp,
++	struct xfs_buf			*agbp,
++	xfs_agino_t			agino,
++	struct xfs_bmap_free		*flist,
++	int				*deleted,
++	xfs_ino_t			*first_ino,
++	struct xfs_inobt_rec_incore	*orec)
+ {
+-	/* REFERENCED */
+-	xfs_agblock_t	agbno;	/* block number containing inode */
+-	xfs_buf_t	*agbp;	/* buffer containing allocation group header */
+-	xfs_agino_t	agino;	/* inode number relative to allocation group */
+-	xfs_agnumber_t	agno;	/* allocation group number */
+-	xfs_agi_t	*agi;	/* allocation group header */
+-	xfs_btree_cur_t	*cur;	/* inode btree cursor */
+-	int		error;	/* error return value */
+-	int		i;	/* result code */
+-	int		ilen;	/* inodes in an inode cluster */
+-	xfs_mount_t	*mp;	/* mount structure for filesystem */
+-	int		off;	/* offset of inode in inode chunk */
+-	xfs_inobt_rec_incore_t rec;	/* btree record */
+-	struct xfs_perag *pag;
++	struct xfs_agi			*agi = XFS_BUF_TO_AGI(agbp);
++	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
++	struct xfs_perag		*pag;
++	struct xfs_btree_cur		*cur;
++	struct xfs_inobt_rec_incore	rec;
++	int				ilen;
++	int				error;
++	int				i;
++	int				off;
+ 
+-	mp = tp->t_mountp;
+-
+-	/*
+-	 * Break up inode number into its components.
+-	 */
+-	agno = XFS_INO_TO_AGNO(mp, inode);
+-	if (agno >= mp->m_sb.sb_agcount)  {
+-		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
+-			__func__, agno, mp->m_sb.sb_agcount);
+-		ASSERT(0);
+-		return XFS_ERROR(EINVAL);
+-	}
+-	agino = XFS_INO_TO_AGINO(mp, inode);
+-	if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
+-		xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
+-			__func__, (unsigned long long)inode,
+-			(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
+-		ASSERT(0);
+-		return XFS_ERROR(EINVAL);
+-	}
+-	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
+-	if (agbno >= mp->m_sb.sb_agblocks)  {
+-		xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
+-			__func__, agbno, mp->m_sb.sb_agblocks);
+-		ASSERT(0);
+-		return XFS_ERROR(EINVAL);
+-	}
+-	/*
+-	 * Get the allocation group header.
+-	 */
+-	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+-	if (error) {
+-		xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
+-			__func__, error);
+-		return error;
+-	}
+-	agi = XFS_BUF_TO_AGI(agbp);
+ 	ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
+-	ASSERT(agbno < be32_to_cpu(agi->agi_length));
++	ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length));
++
+ 	/*
+ 	 * Initialize the cursor.
+ 	 */
+-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
++	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+ 
+ 	error = xfs_check_agi_freecount(cur, agi);
+ 	if (error)
+@@ -1180,7 +1392,7 @@ xfs_difree(
+ 	if (!(mp->m_flags & XFS_MOUNT_IKEEP) &&
+ 	    (rec.ir_freecount == XFS_IALLOC_INODES(mp))) {
+ 
+-		*delete = 1;
++		*deleted = 1;
+ 		*first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
+ 
+ 		/*
+@@ -1208,7 +1420,7 @@ xfs_difree(
+ 				agno, XFS_INO_TO_AGBNO(mp,rec.ir_startino)),
+ 				XFS_IALLOC_BLOCKS(mp), flist, mp);
+ 	} else {
+-		*delete = 0;
++		*deleted = 0;
+ 
+ 		error = xfs_inobt_update(cur, &rec);
+ 		if (error) {
+@@ -1232,6 +1444,7 @@ xfs_difree(
+ 	if (error)
+ 		goto error0;
+ 
++	*orec = rec;
+ 	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+ 	return 0;
+ 
+@@ -1240,6 +1453,189 @@ error0:
+ 	return error;
+ }
+ 
++/*
++ * Free an inode in the free inode btree.
++ */
++STATIC int
++xfs_difree_finobt(
++	struct xfs_mount		*mp,
++	struct xfs_trans		*tp,
++	struct xfs_buf			*agbp,
++	xfs_agino_t			agino,
++	struct xfs_inobt_rec_incore	*ibtrec) /* inobt record */
++{
++	struct xfs_agi			*agi = XFS_BUF_TO_AGI(agbp);
++	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
++	struct xfs_btree_cur		*cur;
++	struct xfs_inobt_rec_incore	rec;
++	int				offset = agino - ibtrec->ir_startino;
++	int				error;
++	int				i;
++
++	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
++
++	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
++	if (error)
++		goto error;
++	if (i == 0) {
++		/*
++		 * If the record does not exist in the finobt, we must have just
++		 * freed an inode in a previously fully allocated chunk. If not,
++		 * something is out of sync.
++		 */
++		XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error);
++
++		error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount,
++					     ibtrec->ir_free, &i);
++		if (error)
++			goto error;
++		ASSERT(i == 1);
++
++		goto out;
++	}
++
++	/*
++	 * Read and update the existing record.
++	 */
++	error = xfs_inobt_get_rec(cur, &rec, &i);
++	if (error)
++		goto error;
++	XFS_WANT_CORRUPTED_GOTO(i == 1, error);
++
++	rec.ir_free |= XFS_INOBT_MASK(offset);
++	rec.ir_freecount++;
++
++	XFS_WANT_CORRUPTED_GOTO((rec.ir_free == ibtrec->ir_free) &&
++				(rec.ir_freecount == ibtrec->ir_freecount),
++				error);
++
++	/*
++	 * The content of inobt records should always match between the inobt
++	 * and finobt. The lifecycle of records in the finobt is different from
++	 * the inobt in that the finobt only tracks records with at least one
++	 * free inode. This is to optimize lookup for inode allocation purposes.
++	 * The following checks determine whether to update the existing record or
++	 * remove it entirely.
++	 */
++
++	if (rec.ir_freecount == XFS_IALLOC_INODES(mp) &&
++	    !(mp->m_flags & XFS_MOUNT_IKEEP)) {
++		/*
++		 * If all inodes are free and we're in !ikeep mode, the entire
++		 * inode chunk has been deallocated. Remove the record from the
++		 * finobt.
++		 */
++		error = xfs_btree_delete(cur, &i);
++		if (error)
++			goto error;
++		ASSERT(i == 1);
++	} else {
++		/*
++		 * The existing finobt record was modified and has a combination
++		 * of allocated and free inodes or is completely free and ikeep
++		 * is enabled. Update the record.
++		 */
++		error = xfs_inobt_update(cur, &rec);
++		if (error)
++			goto error;
++	}
++
++out:
++	error = xfs_check_agi_freecount(cur, agi);
++	if (error)
++		goto error;
++
++	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++	return 0;
++
++error:
++	xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
++	return error;
++}
++
++/*
++ * Free disk inode.  Carefully avoids touching the incore inode, all
++ * manipulations incore are the caller's responsibility.
++ * The on-disk inode is not changed by this operation, only the
++ * btree (free inode mask) is changed.
++ */
++int
++xfs_difree(
++	struct xfs_trans	*tp,		/* transaction pointer */
++	xfs_ino_t		inode,		/* inode to be freed */
++	struct xfs_bmap_free	*flist,		/* extents to free */
++	int			*deleted,/* set if inode cluster was deleted */
++	xfs_ino_t		*first_ino)/* first inode in deleted cluster */
++{
++	/* REFERENCED */
++	xfs_agblock_t		agbno;	/* block number containing inode */
++	struct xfs_buf		*agbp;	/* buffer for allocation group header */
++	xfs_agino_t		agino;	/* allocation group inode number */
++	xfs_agnumber_t		agno;	/* allocation group number */
++	int			error;	/* error return value */
++	struct xfs_mount	*mp;	/* mount structure for filesystem */
++	struct xfs_inobt_rec_incore rec;/* btree record */
++
++	mp = tp->t_mountp;
++
++	/*
++	 * Break up inode number into its components.
++	 */
++	agno = XFS_INO_TO_AGNO(mp, inode);
++	if (agno >= mp->m_sb.sb_agcount)  {
++		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
++			__func__, agno, mp->m_sb.sb_agcount);
++		ASSERT(0);
++		return XFS_ERROR(EINVAL);
++	}
++	agino = XFS_INO_TO_AGINO(mp, inode);
++	if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
++		xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
++			__func__, (unsigned long long)inode,
++			(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
++		ASSERT(0);
++		return XFS_ERROR(EINVAL);
++	}
++	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
++	if (agbno >= mp->m_sb.sb_agblocks)  {
++		xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
++			__func__, agbno, mp->m_sb.sb_agblocks);
++		ASSERT(0);
++		return XFS_ERROR(EINVAL);
++	}
++	/*
++	 * Get the allocation group header.
++	 */
++	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
++	if (error) {
++		xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
++			__func__, error);
++		return error;
++	}
++
++	/*
++	 * Fix up the inode allocation btree.
++	 */
++	error = xfs_difree_inobt(mp, tp, agbp, agino, flist, deleted, first_ino,
++				 &rec);
++	if (error)
++		goto error0;
++
++	/*
++	 * Fix up the free inode btree.
++	 */
++	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
++		error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
++		if (error)
++			goto error0;
++	}
++
++	return 0;
++
++error0:
++	return error;
++}
++
+ STATIC int
+ xfs_imap_lookup(
+ 	struct xfs_mount	*mp,
+@@ -1271,7 +1667,7 @@ xfs_imap_lookup(
+ 	 * we have a record, we need to ensure it contains the inode number
+ 	 * we are looking up.
+ 	 */
+-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
++	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+ 	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
+ 	if (!error) {
+ 		if (i)
+@@ -1482,6 +1878,8 @@ xfs_ialloc_log_agi(
+ 		offsetof(xfs_agi_t, agi_newino),
+ 		offsetof(xfs_agi_t, agi_dirino),
+ 		offsetof(xfs_agi_t, agi_unlinked),
++		offsetof(xfs_agi_t, agi_free_root),
++		offsetof(xfs_agi_t, agi_free_level),
+ 		sizeof(xfs_agi_t)
+ 	};
+ #ifdef DEBUG
+@@ -1491,14 +1889,39 @@ xfs_ialloc_log_agi(
+ 	ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
+ #endif
+ 	/*
+-	 * Compute byte offsets for the first and last fields.
++	 * The growth of the agi buffer over time now requires that we interpret
++	 * the buffer as two logical regions delineated at the end of the unlinked
++	 * list. This is due to the size of the hash table and its location in the
++	 * middle of the agi.
++	 *
++	 * For example, a request to log a field before agi_unlinked and a field
++	 * after agi_unlinked could cause us to log the entire hash table and use
++	 * an excessive amount of log space. To avoid this behavior, log the
++	 * region up through agi_unlinked in one call and the region after
++	 * agi_unlinked through the end of the structure in another.
+ 	 */
+-	xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last);
++	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
++
+ 	/*
+-	 * Log the allocation group inode header buffer.
++	 * Compute byte offsets for the first and last fields in the first
++	 * region and log agi buffer. This only logs up through agi_unlinked.
+ 	 */
+-	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
+-	xfs_trans_log_buf(tp, bp, first, last);
++	if (fields & XFS_AGI_ALL_BITS_R1) {
++		xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1,
++				  &first, &last);
++		xfs_trans_log_buf(tp, bp, first, last);
++	}
++
++	/*
++	 * Mask off the bits in the first region and calculate the first and last
++	 * field offsets for any bits in the second region.
++	 */
++	fields &= ~XFS_AGI_ALL_BITS_R1;
++	if (fields) {
++		xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2,
++				  &first, &last);
++		xfs_trans_log_buf(tp, bp, first, last);
++	}
+ }
+ 
+ #ifdef DEBUG
+diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
+index 0a29d73..c337389 100644
+--- a/libxfs/xfs_ialloc_btree.c
++++ b/libxfs/xfs_ialloc_btree.c
+@@ -30,7 +30,8 @@ xfs_inobt_dup_cursor(
+ 	struct xfs_btree_cur	*cur)
+ {
+ 	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
+-			cur->bc_private.a.agbp, cur->bc_private.a.agno);
++			cur->bc_private.a.agbp, cur->bc_private.a.agno,
++			cur->bc_btnum);
+ }
+ 
+ STATIC void
+@@ -47,6 +48,21 @@ xfs_inobt_set_root(
+ 	xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
+ }
+ 
++STATIC void
++xfs_finobt_set_root(
++	struct xfs_btree_cur	*cur,
++	union xfs_btree_ptr	*nptr,
++	int			inc)	/* level change */
++{
++	struct xfs_buf		*agbp = cur->bc_private.a.agbp;
++	struct xfs_agi		*agi = XFS_BUF_TO_AGI(agbp);
++
++	agi->agi_free_root = nptr->s;
++	be32_add_cpu(&agi->agi_free_level, inc);
++	xfs_ialloc_log_agi(cur->bc_tp, agbp,
++			   XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL);
++}
++
+ STATIC int
+ xfs_inobt_alloc_block(
+ 	struct xfs_btree_cur	*cur,
+@@ -154,6 +170,17 @@ xfs_inobt_init_ptr_from_cur(
+ 	ptr->s = agi->agi_root;
+ }
+ 
++STATIC void
++xfs_finobt_init_ptr_from_cur(
++	struct xfs_btree_cur	*cur,
++	union xfs_btree_ptr	*ptr)
++{
++	struct xfs_agi		*agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
++
++	ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
++	ptr->s = agi->agi_free_root;
++}
++
+ STATIC __int64_t
+ xfs_inobt_key_diff(
+ 	struct xfs_btree_cur	*cur,
+@@ -184,6 +211,7 @@ xfs_inobt_verify(
+ 	 */
+ 	switch (block->bb_magic) {
+ 	case cpu_to_be32(XFS_IBT_CRC_MAGIC):
++	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
+ 		if (!xfs_sb_version_hascrc(&mp->m_sb))
+ 			return false;
+ 		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+@@ -195,6 +223,7 @@ xfs_inobt_verify(
+ 			return false;
+ 		/* fall through */
+ 	case cpu_to_be32(XFS_IBT_MAGIC):
++	case cpu_to_be32(XFS_FIBT_MAGIC):
+ 		break;
+ 	default:
+ 		return 0;
+@@ -371,6 +400,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
+ #endif
+ };
+ 
++static const struct xfs_btree_ops xfs_finobt_ops = {
++	.rec_len		= sizeof(xfs_inobt_rec_t),
++	.key_len		= sizeof(xfs_inobt_key_t),
++
++	.dup_cursor		= xfs_inobt_dup_cursor,
++	.set_root		= xfs_finobt_set_root,
++	.alloc_block		= xfs_inobt_alloc_block,
++	.free_block		= xfs_inobt_free_block,
++	.get_minrecs		= xfs_inobt_get_minrecs,
++	.get_maxrecs		= xfs_inobt_get_maxrecs,
++	.init_key_from_rec	= xfs_inobt_init_key_from_rec,
++	.init_rec_from_key	= xfs_inobt_init_rec_from_key,
++	.init_rec_from_cur	= xfs_inobt_init_rec_from_cur,
++	.init_ptr_from_cur	= xfs_finobt_init_ptr_from_cur,
++	.key_diff		= xfs_inobt_key_diff,
++	.buf_ops		= &xfs_inobt_buf_ops,
++#if defined(DEBUG) || defined(XFS_WARN)
++	.keys_inorder		= xfs_inobt_keys_inorder,
++	.recs_inorder		= xfs_inobt_recs_inorder,
++#endif
++};
++
+ /*
+  * Allocate a new inode btree cursor.
+  */
+@@ -379,7 +430,8 @@ xfs_inobt_init_cursor(
+ 	struct xfs_mount	*mp,		/* file system mount point */
+ 	struct xfs_trans	*tp,		/* transaction pointer */
+ 	struct xfs_buf		*agbp,		/* buffer for agi structure */
+-	xfs_agnumber_t		agno)		/* allocation group number */
++	xfs_agnumber_t		agno,		/* allocation group number */
++	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
+ {
+ 	struct xfs_agi		*agi = XFS_BUF_TO_AGI(agbp);
+ 	struct xfs_btree_cur	*cur;
+@@ -388,11 +440,17 @@ xfs_inobt_init_cursor(
+ 
+ 	cur->bc_tp = tp;
+ 	cur->bc_mp = mp;
+-	cur->bc_nlevels = be32_to_cpu(agi->agi_level);
+-	cur->bc_btnum = XFS_BTNUM_INO;
++	cur->bc_btnum = btnum;
++	if (btnum == XFS_BTNUM_INO) {
++		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
++		cur->bc_ops = &xfs_inobt_ops;
++	} else {
++		cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
++		cur->bc_ops = &xfs_finobt_ops;
++	}
++
+ 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
+ 
+-	cur->bc_ops = &xfs_inobt_ops;
+ 	if (xfs_sb_version_hascrc(&mp->m_sb))
+ 		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
+ 
+diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
+index 7ee4612..ea89367 100644
+--- a/libxfs/xfs_sb.c
++++ b/libxfs/xfs_sb.c
+@@ -408,6 +408,8 @@ xfs_sb_from_disk(
+ 	to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
+ 	to->sb_features_log_incompat =
+ 				be32_to_cpu(from->sb_features_log_incompat);
++	/* crc is only used on disk, not in memory; just init to 0 here. */
++	to->sb_crc = 0;
+ 	to->sb_pad = 0;
+ 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
+ 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+@@ -485,6 +487,9 @@ xfs_sb_to_disk(
+ 	if (!fields)
+ 		return;
+ 
++	/* We should never write the crc here, it's updated in the IO path */
++	fields &= ~XFS_SB_CRC;
++
+ 	xfs_sb_quota_to_disk(to, from, &fields);
+ 	while (fields) {
+ 		f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
+diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
+index 1e59fad..870d4fc 100644
+--- a/libxfs/xfs_trans_resv.c
++++ b/libxfs/xfs_trans_resv.c
+@@ -81,6 +81,37 @@ xfs_calc_inode_res(
+ }
+ 
+ /*
++ * The free inode btree is a conditional feature and the log reservation
++ * requirements differ slightly from that of the traditional inode allocation
++ * btree. The finobt tracks records for inode chunks with at least one free inode.
++ * Therefore, a record can be removed from the tree for an inode allocation or
++ * free and the associated merge reservation is unconditional. This also covers
++ * the possibility of a split on record insertion.
++ *
++ * the free inode btree: max depth * block size
++ * the free inode btree entry: block size
++ *
++ * TODO: is the modify res really necessary? covered by the merge/split res?
++ * This seems to be the pattern of ifree, but not create_resv_alloc. Why?
++ */
++STATIC uint
++xfs_calc_finobt_res(
++	struct xfs_mount 	*mp,
++	int			modify)
++{
++	uint res;
++
++	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
++		return 0;
++
++	res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
++	if (modify)
++		res += (uint)XFS_FSB_TO_B(mp, 1);
++
++	return res;
++}
++
++/*
+  * Various log reservation values.
+  *
+  * These are based on the size of the file system block because that is what
+@@ -250,6 +281,7 @@ xfs_calc_remove_reservation(
+  *    the superblock for the nlink flag: sector size
+  *    the directory btree: (max depth + v2) * dir block size
+  *    the directory inode's bmap btree: (max depth + v2) * block size
++ *    the finobt
+  */
+ STATIC uint
+ xfs_calc_create_resv_modify(
+@@ -258,7 +290,8 @@ xfs_calc_create_resv_modify(
+ 	return xfs_calc_inode_res(mp, 2) +
+ 		xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
+ 		(uint)XFS_FSB_TO_B(mp, 1) +
+-		xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
++		xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
++		xfs_calc_finobt_res(mp, 1);
+ }
+ 
+ /*
+@@ -268,6 +301,7 @@ xfs_calc_create_resv_modify(
+  *    the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
+  *    the inode btree: max depth * blocksize
+  *    the allocation btrees: 2 trees * (max depth - 1) * block size
++ *    the finobt
+  */
+ STATIC uint
+ xfs_calc_create_resv_alloc(
+@@ -278,7 +312,8 @@ xfs_calc_create_resv_alloc(
+ 		xfs_calc_buf_res(XFS_IALLOC_BLOCKS(mp), XFS_FSB_TO_B(mp, 1)) +
+ 		xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
+ 		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+-				 XFS_FSB_TO_B(mp, 1));
++				 XFS_FSB_TO_B(mp, 1)) +
++		xfs_calc_finobt_res(mp, 0);
+ }
+ 
+ STATIC uint
+@@ -296,6 +331,7 @@ __xfs_calc_create_reservation(
+  *    the superblock for the nlink flag: sector size
+  *    the inode btree: max depth * blocksize
+  *    the allocation btrees: 2 trees * (max depth - 1) * block size
++ *    the finobt
+  */
+ STATIC uint
+ xfs_calc_icreate_resv_alloc(
+@@ -305,7 +341,8 @@ xfs_calc_icreate_resv_alloc(
+ 		mp->m_sb.sb_sectsize +
+ 		xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
+ 		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+-				 XFS_FSB_TO_B(mp, 1));
++				 XFS_FSB_TO_B(mp, 1)) +
++		xfs_calc_finobt_res(mp, 0);
+ }
+ 
+ STATIC uint
+@@ -359,6 +396,7 @@ xfs_calc_symlink_reservation(
+  *    the on disk inode before ours in the agi hash list: inode cluster size
+  *    the inode btree: max depth * blocksize
+  *    the allocation btrees: 2 trees * (max depth - 1) * block size
++ *    the finobt
+  */
+ STATIC uint
+ xfs_calc_ifree_reservation(
+@@ -374,7 +412,8 @@ xfs_calc_ifree_reservation(
+ 		xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
+ 				 mp->m_in_maxlevels, 0) +
+ 		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+-				 XFS_FSB_TO_B(mp, 1));
++				 XFS_FSB_TO_B(mp, 1)) +
++		xfs_calc_finobt_res(mp, 1);
+ }
+ 
+ /*
+diff --git a/man/man5/xfs.5 b/man/man5/xfs.5
+index 0f490f0..5e47c4c 100644
+--- a/man/man5/xfs.5
++++ b/man/man5/xfs.5
+@@ -1,6 +1,6 @@
+ .TH xfs 5
+ .SH NAME
+-xfs \- layout of the XFS filesystem
++xfs \- layout and mount options for the XFS filesystem
+ .SH DESCRIPTION
+ An XFS filesystem can reside on a regular disk partition or on a
+ logical volume.
+@@ -98,9 +98,210 @@ and by-handle (see
+ .BR open_by_handle (3))
+ interfaces.
+ .SH MOUNT OPTIONS
+-Refer to the
++The following XFS-specific mount options may be used when mounting
++an XFS filesystem. Other generic options may be used as well; refer to the
+ .BR mount (8)
+-manual entry for descriptions of the individual XFS mount options.
++manual page for more details.
++.TP
++.B allocsize=size
++Sets the buffered I/O end-of-file preallocation size when
++doing delayed allocation writeout. Valid values for this
++option are page size (typically 4KiB) through to 1GiB,
++inclusive, in power-of-2 increments.
++.sp
++The default behavior is for dynamic end-of-file
++preallocation size, which uses a set of heuristics to
++optimise the preallocation size based on the current
++allocation patterns within the file and the access patterns
++to the file. Specifying a fixed allocsize value turns off
++the dynamic behavior.
++.TP
++.BR attr2 | noattr2
++The options enable/disable an "opportunistic" improvement to
++be made in the way inline extended attributes are stored
++on-disk.  When the new form is used for the first time when
++attr2 is selected (either when setting or removing extended
++attributes) the on-disk superblock feature bit field will be
++updated to reflect this format being in use.
++.sp
++The default behavior is determined by the on-disk feature
++bit indicating that attr2 behavior is active. If either
++mount option it set, then that becomes the new default used
++by the filesystem.
++.sp
++CRC enabled filesystems always use the attr2 format, and so
++will reject the noattr2 mount option if it is set.
++.TP
++.BR barrier | nobarrier
++Enables/disables the use of block layer write barriers for
++writes into the journal and for data integrity operations.
++This allows for drive level write caching to be enabled, for
++devices that support write barriers.
++.sp
++Barriers are enabled by default.
++.TP
++.BR discard | nodiscard
++Enable/disable the issuing of commands to let the block
++device reclaim space freed by the filesystem.  This is
++useful for SSD devices, thinly provisioned LUNs and virtual
++machine images, but may have a performance impact.
++.sp
++Note: It is currently recommended that you use the fstrim
++application to discard unused blocks rather than the discard
++mount option because the performance impact of this option
++is quite severe.  For this reason, nodiscard is the default.
++.TP
++.BR grpid | bsdgroups | nogrpid | sysvgroups
++These options define what group ID a newly created file
++gets.  When grpid is set, it takes the group ID of the
++directory in which it is created; otherwise it takes the
++fsgid of the current process, unless the directory has the
++setgid bit set, in which case it takes the gid from the
++parent directory, and also gets the setgid bit set if it is
++a directory itself.
++.TP
++.B filestreams
++Make the data allocator use the filestreams allocation mode
++across the entire filesystem rather than just on directories
++configured to use it.
++.TP
++.BR ikeep | noikeep
++When ikeep is specified, XFS does not delete empty inode
++clusters and keeps them around on disk.  When noikeep is
++specified, empty inode clusters are returned to the free
++space pool.  noikeep is the default.
++.TP
++.BR inode32 | inode64
++When inode32 is specified, it indicates that XFS limits
++inode creation to locations which will not result in inode
++numbers with more than 32 bits of significance.
++.sp
++When inode64 is specified, it indicates that XFS is allowed
++to create inodes at any location in the filesystem,
++including those which will result in inode numbers occupying
++more than 32 bits of significance.
++.sp
++inode32 is provided for backwards compatibility with older
++systems and applications, since 64 bits inode numbers might
++cause problems for some applications that cannot handle
++large inode numbers.  If applications are in use which do
++not handle inode numbers bigger than 32 bits, the inode32
++option should be specified.
++.sp
++For kernel v3.7 and later, inode64 is the default.
++.TP
++.BR  largeio | nolargeio
++If "nolargeio" is specified, the optimal I/O reported in
++st_blksize by stat(2) will be as small as possible to allow
++user applications to avoid inefficient read/modify/write
++I/O.  This is typically the page size of the machine, as
++this is the granularity of the page cache.
++.sp
++If "largeio" specified, a filesystem that was created with a
++"swidth" specified will return the "swidth" value (in bytes)
++in st_blksize. If the filesystem does not have a "swidth"
++specified but does specify an "allocsize" then "allocsize"
++(in bytes) will be returned instead. Otherwise the behavior
++is the same as if "nolargeio" was specified.  nolargeio
++is the default.
++.TP
++.B logbufs=value
++Set the number of in-memory log buffers.  Valid numbers
++range from 2\(en8 inclusive.
++.sp
++The default value is 8 buffers.
++.sp
++If the memory cost of 8 log buffers is too high on small
++systems, then it may be reduced at some cost to performance
++on metadata intensive workloads. The logbsize option below
++controls the size of each buffer and so is also relevant to
++this case.
++.TP
++.B logbsize=value
++Set the size of each in-memory log buffer.  The size may be
++specified in bytes, or in kibibytes (KiB) with a "k" suffix.
++Valid sizes for version 1 and version 2 logs are 16384 (value=16k)
++and 32768 (value=32k).  Valid sizes for version 2 logs also
++include 65536 (value=64k), 131072 (value=128k) and 262144 (value=256k). The
++logbsize must be an integer multiple of the log
++stripe unit configured at mkfs time.
++.sp
++The default value for version 1 logs is 32768, while the
++default value for version 2 logs is MAX(32768, log_sunit).
++.TP
++.BR logdev=device and rtdev=device
++Use an external log (metadata journal) and/or real-time device.
++An XFS filesystem has up to three parts: a data section, a log
++section, and a real-time section.  The real-time section is
++optional, and the log section can be separate from the data
++section or contained within it.
++.TP
++.B noalign
++Data allocations will not be aligned at stripe unit
++boundaries. This is only relevant to filesystems created
++with non-zero data alignment parameters (sunit, swidth) by
++mkfs.
++.TP
++.B norecovery
++The filesystem will be mounted without running log recovery.
++If the filesystem was not cleanly unmounted, it is likely to
++be inconsistent when mounted in "norecovery" mode.
++Some files or directories may not be accessible because of this.
++Filesystems mounted "norecovery" must be mounted read-only or
++the mount will fail.
++.TP
++.B nouuid
++Don't check for double mounted file systems using the file
++system uuid.  This is useful to mount LVM snapshot volumes,
++and often used in combination with "norecovery" for mounting
++read-only snapshots.
++.TP
++.B noquota
++Forcibly turns off all quota accounting and enforcement
++within the filesystem.
++.TP
++.B uquota/usrquota/uqnoenforce/quota
++User disk quota accounting enabled, and limits (optionally)
++enforced.  Refer to xfs_quota(8) for further details.
++.TP
++.B gquota/grpquota/gqnoenforce
++Group disk quota accounting enabled and limits (optionally)
++enforced.  Refer to xfs_quota(8) for further details.
++.TP
++.B pquota/prjquota/pqnoenforce
++Project disk quota accounting enabled and limits (optionally)
++enforced.  Refer to xfs_quota(8) for further details.
++.TP
++.BR sunit=value " and " swidth=value
++Used to specify the stripe unit and width for a RAID device
++or a stripe volume.  "value" must be specified in 512-byte
++block units. These options are only relevant to filesystems
++that were created with non-zero data alignment parameters.
++.sp
++The sunit and swidth parameters specified must be compatible
++with the existing filesystem alignment characteristics.  In
++general, that means the only valid changes to sunit are
++increasing it by a power-of-2 multiple. Valid swidth values
++are any integer multiple of a valid sunit value.
++.sp
++Typically the only time these mount options are necessary if
++after an underlying RAID device has had it's geometry
++modified, such as adding a new disk to a RAID5 lun and
++reshaping it.
++.TP
++.B swalloc
++Data allocations will be rounded up to stripe width boundaries
++when the current end of file is being extended and the file
++size is larger than the stripe width size.
++.TP
++.B wsync
++When specified, all filesystem namespace operations are
++executed synchronously. This ensures that when the namespace
++operation (create, unlink, etc) completes, the change to the
++namespace is on stable storage. This is useful in HA setups
++where failover must not result in clients seeing
++inconsistent namespace presentation during or after a
++failover event.
+ .SH SEE ALSO
+ .BR xfsctl (3),
+ .BR mount (8),
+diff --git a/man/man8/mkfs.xfs.8 b/man/man8/mkfs.xfs.8
+index 8184e10..ad9ff3d 100644
+--- a/man/man8/mkfs.xfs.8
++++ b/man/man8/mkfs.xfs.8
+@@ -7,6 +7,9 @@ mkfs.xfs \- construct an XFS filesystem
+ .B \-b
+ .I block_size
+ ] [
++.B \-m
++.I global_metadata_options
++] [
+ .B \-d
+ .I data_section_options
+ ] [
+@@ -125,6 +128,48 @@ The default value is 4096 bytes (4 KiB), the minimum is 512, and the
+ maximum is 65536 (64 KiB).
+ XFS on Linux currently only supports pagesize or smaller blocks.
+ .TP
++.BI \-m " global_metadata_options"
++These options specify metadata format options that either apply to the entire
++filesystem or aren't easily characterised by a specific functionality group. The
++valid
++.I global_metadata_options
++are:
++.RS 1.2i
++.TP
++.BI crc= value
++This is used to create a filesystem which maintains and checks CRC information
++in all metadata objects on disk. The value is either 0 to disable the feature,
++or 1 to enable the use of CRCs.
++.IP
++CRCs enable enhanced error detection due to hardware issues, whilst the format
++changes also improves crash recovery algorithms and the ability of various tools
++to validate and repair metadata corruptions when they are found.  The CRC
++algorithm used is CRC32c, so the overhead is dependent on CPU architecture as
++some CPUs have hardware acceleration of this algorithm.  Typically the overhead
++of calculating and checking the CRCs is not noticable in normal operation.
++.IP
++By default,
++.B mkfs.xfs
++will not enable metadata CRCs.
++.TP
++.BI finobt= value
++This option enables the use of a separate free inode btree index in each
++allocation group. The value is either 0 to disable the feature, or 1 to create
++a free inode btree in each allocation group.
++.IP
++The free inode btree mirrors the existing allocated inode btree index which
++indexes both used and free inodes. The free inode btree does not index used
++inodes, allowing faster, more consistent inode allocation performance as
++filesystems age.
++.IP
++By default,
++.B mkfs.xfs
++will not create free inode btrees. This feature is also currently only available
++for filesystems created with the
++.B \-m crc=1
++option set.
++.RE
++.TP
+ .BI \-d " data_section_options"
+ These options specify the location, size, and other parameters of the
+ data section of the filesystem. The valid
+diff --git a/man/man8/xfs_check.8 b/man/man8/xfs_check.8
+deleted file mode 100644
+index 23027ca..0000000
+--- a/man/man8/xfs_check.8
++++ /dev/null
+@@ -1,203 +0,0 @@
+-.TH xfs_check 8
+-.SH NAME
+-xfs_check \- check XFS filesystem consistency
+-.SH SYNOPSIS
+-.B xfs_check
+-[
+-.B \-i
+-.I ino
+-] ... [
+-.B \-b
+-.I bno
+-] ... [
+-.B \-f
+-] [
+-.B \-s
+-] [
+-.B \-v
+-] [
+-.B \-l
+-.I logdev
+-]
+-.I device
+-.br
+-.B xfs_check \-V
+-.SH DESCRIPTION
+-.B xfs_check
+-checks whether an XFS filesystem is consistent.
+-It is normally run only when there is reason to believe that the
+-filesystem has a consistency problem.
+-The filesystem to be checked is specified by the
+-.I device
+-argument, which should be the disk or volume device for the filesystem.
+-Filesystems stored in files can also be checked, using the
+-.B \-f
+-flag. The filesystem should normally be unmounted or read-only
+-during the execution of
+-.BR xfs_check .
+-Otherwise, spurious problems are reported.
+-.PP
+-Note that
+-.B xfs_check
+-is deprecated and scheduled for removal in June 2014. Please use
+-.BR xfs_repair " " \-n
+-instead.
+-.SH
+-OPTIONS
+-.TP
+-.B \-f
+-Specifies that the filesystem image to be processed is stored in a
+-regular file at
+-.I device
+-(see the
+-.BR mkfs.xfs "(8) " \-d
+-.I file
+-option). This might happen if an image copy
+-of a filesystem has been made into an ordinary file.
+-.TP
+-.BI \-l " logdev"
+-Specifies the device where the filesystem's external log resides.
+-Only for those filesystems which use an external log. See the
+-.BR mkfs.xfs "(8) " \-l
+-option, and refer to
+-.BR xfs (5)
+-for a detailed description of the XFS log.
+-.TP
+-.B \-s
+-Specifies that only serious errors should be reported.
+-Serious errors are those that make it impossible to find major data
+-structures in the filesystem. This option can be used to cut down the
+-amount of output when there is a serious problem, when the output
+-might make it difficult to see what the real problem is.
+-.TP
+-.B \-v
+-Specifies verbose output; it is impossibly long for a
+-reasonably-sized filesystem.
+-This option is intended for internal use only.
+-.TP
+-.BI \-i " ino"
+-Specifies verbose behavior for the specified inode
+-.IR ino .
+-For instance, it can be used to locate all the blocks
+-associated with a given inode.
+-.TP
+-.BI \-b " bno"
+-Specifies verbose behavior for the specific filesystem block at
+-.IR bno .
+-For instance, it can be used to determine what a specific block
+-is used for. The block number is a "file system block number".
+-Conversion between disk addresses (i.e. addresses reported by
+-.BR xfs_bmap (8))
+-and file system blocks may be accomplished using
+-.BR xfs_db "(8)'s " convert
+-command.
+-.TP
+-.B \-V
+-Prints the version number and exits.
+-.PP
+-Any output that is produced when
+-.B xfs_check
+-is not run in verbose mode indicates that the filesystem has an
+-inconsistency. The filesystem can be repaired using either
+-.BR xfs_repair (8)
+-to fix the filesystem in place, or by using
+-.BR xfsdump (8)
+-and
+-.BR mkfs.xfs (8)
+-to dump the filesystem, make a new filesystem, then use
+-.BR xfsrestore (8)
+-to restore the data onto the new filesystem.
+-Note that xfsdump may fail on a corrupt filesystem.
+-However, if the filesystem is mountable, xfsdump can
+-be used to try and save important data before
+-repairing the filesystem with xfs_repair.
+-If the filesystem is not mountable though, xfs_repair is
+-the only viable option.
+-.SH DIAGNOSTICS
+-If the filesystem is completely corrupt, a core dump might
+-be produced instead of the message
+-.RS
+-.I device
+-.B is not a valid filesystem
+-.RE
+-.PP
+-If the filesystem is very large (has many files) then
+-.B xfs_check
+-might run out of memory. In this case the message
+-.RS
+-.B out of memory
+-.RE
+-is printed.
+-.PP
+-The following is a description of the most likely problems and the associated
+-messages.
+-Most of the diagnostics produced are only meaningful with an understanding
+-of the structure of the filesystem.
+-.TP
+-.BI "agf_freeblks " n ", counted " m " in ag " a
+-The freeblocks count in the allocation group header for allocation group
+-.I a
+-doesn't match the number of blocks counted free.
+-.TP
+-.BI "agf_longest " n ", counted " m " in ag " a
+-The longest free extent in the allocation group header for allocation group
+-.I a
+-doesn't match the longest free extent found in the allocation group.
+-.TP
+-.BI "agi_count " n ", counted " m " in ag " a
+-The allocated inode count in the allocation group header for allocation group
+-.I a
+-doesn't match the number of inodes counted in the allocation group.
+-.TP
+-.BI "agi_freecount " n ", counted " m " in ag " a
+-The free inode count in the allocation group header for allocation group
+-.I a
+-doesn't match the number of inodes counted free in the allocation group.
+-.TP
+-.BI "block " a/b " expected inum 0 got " i
+-The block number is specified as a pair
+-(allocation group number, block in the allocation group).
+-The block is used multiple times (shared), between multiple inodes.
+-This message usually follows a message of the next type.
+-.TP
+-.BI "block " a/b " expected type unknown got " y
+-The block is used multiple times (shared).
+-.TP
+-.BI "block " a/b " type unknown not expected
+-The block is unaccounted for (not in the freelist and not in use).
+-.TP
+-.BI "link count mismatch for inode " nnn " (name " xxx "), nlink " m ", counted " n
+-The inode has a bad link count (number of references in directories).
+-.TP
+-.BI "rtblock " b " expected inum 0 got " i
+-The block is used multiple times (shared), between multiple inodes.
+-This message usually follows a message of the next type.
+-.TP
+-.BI "rtblock " b " expected type unknown got " y
+-The real-time block is used multiple times (shared).
+-.TP
+-.BI "rtblock " b " type unknown not expected
+-The real-time block is unaccounted for (not in the freelist and not in use).
+-.TP
+-.BI "sb_fdblocks " n ", counted " m
+-The number of free data blocks recorded
+-in the superblock doesn't match the number counted free in the filesystem.
+-.TP
+-.BI "sb_frextents " n ", counted " m
+-The number of free real-time extents recorded
+-in the superblock doesn't match the number counted free in the filesystem.
+-.TP
+-.BI "sb_icount " n ", counted " m
+-The number of allocated inodes recorded
+-in the superblock doesn't match the number allocated in the filesystem.
+-.TP
+-.BI "sb_ifree " n ", counted " m
+-The number of free inodes recorded
+-in the superblock doesn't match the number free in the filesystem.
+-.SH SEE ALSO
+-.BR mkfs.xfs (8),
+-.BR xfsdump (8),
+-.BR xfsrestore (8),
+-.BR xfs_ncheck (8),
+-.BR xfs_repair (8),
+-.BR xfs (5).
+diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
+index 7a43a2c..4d8d4ff 100644
+--- a/man/man8/xfs_db.8
++++ b/man/man8/xfs_db.8
+@@ -38,8 +38,7 @@ commands may be run interactively (the default) or as arguments
+ on the command line. Multiple
+ .B \-c
+ arguments may be given. The commands are run in the sequence given,
+-then the program exits. This is the mechanism used to implement
+-.BR xfs_check (8).
++then the program exits.
+ .TP
+ .B \-f
+ Specifies that the filesystem image to be processed is stored in a
+@@ -56,14 +55,11 @@ an ordinary file with
+ .B \-F
+ Specifies that we want to continue even if the superblock magic is not
+ correct.  For use in
+-.BR xfs_check
+-and
+ .BR xfs_metadump .
+ .TP
+ .B \-i
+ Allows execution on a mounted filesystem, provided it is mounted read-only.
+-Useful for shell scripts such as
+-.BR xfs_check (8),
++Useful for shell scripts
+ which must only operate on filesystems in a guaranteed consistent state
+ (either unmounted or mounted read-only). These semantics are slightly
+ different to that of the
+@@ -204,9 +200,7 @@ command can be given, presumably with different arguments than the previous one.
+ Get block usage and check filesystem consistency.
+ The information is saved for use by a subsequent
+ .BR blockuse ", " ncheck ", or " blocktrash
+-command. See
+-.BR xfs_check (8)
+-for more information.
++command.
+ .RS 1.0i
+ .TP 0.4i
+ .B \-b
+@@ -244,7 +238,7 @@ Trashing occurs to randomly selected bits in the chosen blocks.
+ This command is available only in debugging versions of
+ .BR xfs_db .
+ It is useful for testing
+-.BR xfs_repair "(8) and " xfs_check (8).
++.BR xfs_repair "(8).
+ .RS 1.0i
+ .TP 0.4i
+ .BR \-0 " | " -1 " | " -2 " | " -3
+@@ -1856,12 +1850,60 @@ and printable ASCII chars.
+ Many messages can come from the
+ .B check
+ .RB ( blockget )
+-command; these are documented in
+-.BR xfs_check (8).
++command.
++If the filesystem is completely corrupt, a core dump might
++be produced instead of the message
++.RS
++.I device
++.B is not a valid filesystem
++.RE
++.PP
++If the filesystem is very large (has many files) then
++.B check
++might run out of memory. In this case the message
++.RS
++.B out of memory
++.RE
++is printed.
++.PP
++The following is a description of the most likely problems and the associated
++messages.
++Most of the diagnostics produced are only meaningful with an understanding
++of the structure of the filesystem.
++.TP
++.BI "agf_freeblks " n ", counted " m " in ag " a
++The freeblocks count in the allocation group header for allocation group
++.I a
++doesn't match the number of blocks counted free.
++.TP
++.BI "agf_longest " n ", counted " m " in ag " a
++The longest free extent in the allocation group header for allocation group
++.I a
++doesn't match the longest free extent found in the allocation group.
++.TP
++.BI "agi_count " n ", counted " m " in ag " a
++The allocated inode count in the allocation group header for allocation group
++.I a
++doesn't match the number of inodes counted in the allocation group.
++.TP
++.BI "agi_freecount " n ", counted " m " in ag " a
++The free inode count in the allocation group header for allocation group
++.I a
++doesn't match the number of inodes counted free in the allocation group.
++.TP
++.BI "block " a/b " expected inum 0 got " i
++The block number is specified as a pair
++(allocation group number, block in the allocation group).
++The block is used multiple times (shared), between multiple inodes.
++This message usually follows a message of the next type.
++.TP
++.BI "block " a/b " expected type unknown got " y
++The block is used multiple times (shared).
++.TP
++.BI "block " a/b " type unknown not expected
+ .SH SEE ALSO
+ .BR mkfs.xfs (8),
+ .BR xfs_admin (8),
+-.BR xfs_check (8),
+ .BR xfs_copy (8),
+ .BR xfs_logprint (8),
+ .BR xfs_metadump (8),
+diff --git a/man/man8/xfs_mdrestore.8 b/man/man8/xfs_mdrestore.8
+index 51297c4..0957d81 100644
+--- a/man/man8/xfs_mdrestore.8
++++ b/man/man8/xfs_mdrestore.8
+@@ -48,7 +48,6 @@ returns an exit code of 0 if all the metadata is successfully restored or
+ .SH SEE ALSO
+ .BR xfs_metadump (8),
+ .BR xfs_repair (8),
+-.BR xfs_check (8),
+ .BR xfs (5)
+ .SH BUGS
+ Email bug reports to
+diff --git a/man/man8/xfs_ncheck.8 b/man/man8/xfs_ncheck.8
+index 4099772..5ae72b2 100644
+--- a/man/man8/xfs_ncheck.8
++++ b/man/man8/xfs_ncheck.8
+@@ -63,13 +63,12 @@ May be given multiple times to select multiple inode numbers.
+ Prints the version number and exits.
+ .PP
+ If the filesystem is seriously corrupted, or very busy and looks
+-like it is corrupt, a message of the form that would be generated by
+-.BR xfs_check (8)
+-may appear.
++like it is corrupt, a message of the form that would be generated by the
++.BR xfs_db (8)
++"check" command may appear.
+ .PP
+ .B xfs_ncheck
+ is only useful with XFS filesystems.
+ .SH SEE ALSO
+ .BR mkfs.xfs (8),
+-.BR xfs_check (8),
+ .BR xfs (5).
+diff --git a/man/man8/xfs_repair.8 b/man/man8/xfs_repair.8
+index b7c2d8c..0394c50 100644
+--- a/man/man8/xfs_repair.8
++++ b/man/man8/xfs_repair.8
+@@ -548,6 +548,5 @@ fixed and/or improved.
+ .BR mkfs.xfs (8),
+ .BR umount (8),
+ .BR xfs_admin (8),
+-.BR xfs_check (8),
+ .BR xfs_metadump (8),
+ .BR xfs (5).
+diff --git a/mkfs/proto.c b/mkfs/proto.c
+index 5a47e27..72068f0 100644
+--- a/mkfs/proto.c
++++ b/mkfs/proto.c
+@@ -197,7 +197,6 @@ rsvfile(
+ 	tp = libxfs_trans_alloc(mp, 0);
+ 
+ 	libxfs_trans_ijoin(tp, ip, 0);
+-	libxfs_trans_ihold(tp, ip);
+ 
+ 	ip->i_d.di_mode &= ~S_ISUID;
+ 
+@@ -464,7 +463,6 @@ parseproto(
+ 		libxfs_trans_ijoin(tp, pip, 0);
+ 		xname.type = XFS_DIR3_FT_REG_FILE;
+ 		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
+-		libxfs_trans_ihold(tp, pip);
+ 		break;
+ 
+ 	case IF_RESERVED:			/* pre-allocated space only */
+@@ -481,7 +479,6 @@ parseproto(
+ 
+ 		xname.type = XFS_DIR3_FT_REG_FILE;
+ 		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
+-		libxfs_trans_ihold(tp, pip);
+ 		libxfs_trans_log_inode(tp, ip, flags);
+ 
+ 		error = libxfs_bmap_finish(&tp, &flist, &committed);
+@@ -489,6 +486,7 @@ parseproto(
+ 			fail(_("Pre-allocated file creation failed"), error);
+ 		libxfs_trans_commit(tp, 0);
+ 		rsvfile(mp, ip, llen);
++		IRELE(ip);
+ 		return;
+ 
+ 	case IF_BLOCK:
+@@ -503,7 +501,6 @@ parseproto(
+ 		libxfs_trans_ijoin(tp, pip, 0);
+ 		xname.type = XFS_DIR3_FT_BLKDEV;
+ 		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
+-		libxfs_trans_ihold(tp, pip);
+ 		flags |= XFS_ILOG_DEV;
+ 		break;
+ 
+@@ -518,7 +515,6 @@ parseproto(
+ 		libxfs_trans_ijoin(tp, pip, 0);
+ 		xname.type = XFS_DIR3_FT_CHRDEV;
+ 		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
+-		libxfs_trans_ihold(tp, pip);
+ 		flags |= XFS_ILOG_DEV;
+ 		break;
+ 
+@@ -531,7 +527,6 @@ parseproto(
+ 		libxfs_trans_ijoin(tp, pip, 0);
+ 		xname.type = XFS_DIR3_FT_FIFO;
+ 		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
+-		libxfs_trans_ihold(tp, pip);
+ 		break;
+ 	case IF_SYMLINK:
+ 		buf = getstr(pp);
+@@ -545,7 +540,6 @@ parseproto(
+ 		libxfs_trans_ijoin(tp, pip, 0);
+ 		xname.type = XFS_DIR3_FT_SYMLINK;
+ 		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
+-		libxfs_trans_ihold(tp, pip);
+ 		break;
+ 	case IF_DIRECTORY:
+ 		getres(tp, 0);
+@@ -565,7 +559,6 @@ parseproto(
+ 			newdirent(mp, tp, pip, &xname, ip->i_ino,
+ 				  &first, &flist);
+ 			pip->i_d.di_nlink++;
+-			libxfs_trans_ihold(tp, pip);
+ 			libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
+ 		}
+ 		newdirectory(mp, tp, ip, pip);
+@@ -573,7 +566,6 @@ parseproto(
+ 		error = libxfs_bmap_finish(&tp, &flist, &committed);
+ 		if (error)
+ 			fail(_("Directory creation failed"), error);
+-		libxfs_trans_ihold(tp, ip);
+ 		libxfs_trans_commit(tp, 0);
+ 		/*
+ 		 * RT initialization.  Do this here to ensure that
+@@ -590,7 +582,7 @@ parseproto(
+ 				break;
+ 			parseproto(mp, ip, fsxp, pp, name);
+ 		}
+-		libxfs_iput(ip, 0);
++		IRELE(ip);
+ 		return;
+ 	default:
+ 		ASSERT(0);
+@@ -603,6 +595,7 @@ parseproto(
+ 			error);
+ 	}
+ 	libxfs_trans_commit(tp, 0);
++	IRELE(ip);
+ }
+ 
+ void
+@@ -665,7 +658,6 @@ rtinit(
+ 	*(__uint64_t *)&rbmip->i_d.di_atime = 0;
+ 	libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE);
+ 	libxfs_mod_sb(tp, XFS_SB_RBMINO);
+-	libxfs_trans_ihold(tp, rbmip);
+ 	mp->m_rbmip = rbmip;
+ 	error = libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0,
+ 					&creds, &fsxattrs, &rsumip);
+@@ -676,7 +668,6 @@ rtinit(
+ 	rsumip->i_d.di_size = mp->m_rsumsize;
+ 	libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE);
+ 	libxfs_mod_sb(tp, XFS_SB_RSUMINO);
+-	libxfs_trans_ihold(tp, rsumip);
+ 	libxfs_trans_commit(tp, 0);
+ 	mp->m_rsumip = rsumip;
+ 	/*
+@@ -689,7 +680,6 @@ rtinit(
+ 		res_failed(i);
+ 
+ 	libxfs_trans_ijoin(tp, rbmip, 0);
+-	libxfs_trans_ihold(tp, rbmip);
+ 	bno = 0;
+ 	xfs_bmap_init(&flist, &first);
+ 	while (bno < mp->m_sb.sb_rbmblocks) {
+@@ -726,7 +716,6 @@ rtinit(
+ 	if (i)
+ 		res_failed(i);
+ 	libxfs_trans_ijoin(tp, rsumip, 0);
+-	libxfs_trans_ihold(tp, rsumip);
+ 	bno = 0;
+ 	xfs_bmap_init(&flist, &first);
+ 	while (bno < nsumblocks) {
+@@ -762,7 +751,6 @@ rtinit(
+ 		if (i)
+ 			res_failed(i);
+ 		libxfs_trans_ijoin(tp, rbmip, 0);
+-		libxfs_trans_ihold(tp, rbmip);
+ 		xfs_bmap_init(&flist, &first);
+ 		ebno = XFS_RTMIN(mp->m_sb.sb_rextents,
+ 			bno + NBBY * mp->m_sb.sb_blocksize);
+diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
+index 37c05a9..c85258a 100644
+--- a/mkfs/xfs_mkfs.c
++++ b/mkfs/xfs_mkfs.c
+@@ -183,6 +183,8 @@ char	*sopts[] = {
+ char	*mopts[] = {
+ #define	M_CRC		0
+ 	"crc",
++#define M_FINOBT	1
++	"finobt",
+ 	NULL
+ };
+ 
+@@ -455,11 +457,30 @@ static void get_topology(
+ 	int			force_overwrite)
+ {
+ 	if (!xi->disfile) {
+-		const char *dfile = xi->volname ? xi->volname : xi->dname;
++		char *dfile = xi->volname ? xi->volname : xi->dname;
++		struct stat statbuf;
+ 
+-		blkid_get_topology(dfile, &ft->dsunit, &ft->dswidth,
+-				   &ft->lsectorsize, &ft->psectorsize,
+-				   force_overwrite);
++		/*
++		 * If our target is a regular file, and xi->disfile isn't
++		 * set (i.e. no "-d file" invocation), use platform_findsizes
++		 * to try to obtain the underlying filesystem's requirements
++		 * for direct IO; we'll set our sector size to that if possible.
++		 */
++		if (!stat(dfile, &statbuf) && S_ISREG(statbuf.st_mode)) {
++			int fd;
++			long long dummy;
++
++			fd = open(dfile, O_RDONLY);
++			if (fd >= 0) {
++				platform_findsizes(dfile, fd, &dummy,
++						   &ft->lsectorsize);
++				close(fd);
++			}
++		} else {
++			blkid_get_topology(dfile, &ft->dsunit, &ft->dswidth,
++					   &ft->lsectorsize, &ft->psectorsize,
++					   force_overwrite);
++		}
+ 	}
+ 
+ 	if (xi->rtname && !xi->risfile) {
+@@ -962,6 +983,7 @@ main(
+ 	struct fs_topology	ft;
+ 	int			lazy_sb_counters;
+ 	int			crcs_enabled;
++	int			finobt;
+ 
+ 	progname = basename(argv[0]);
+ 	setlocale(LC_ALL, "");
+@@ -995,6 +1017,7 @@ main(
+ 	worst_freelist = 0;
+ 	lazy_sb_counters = 1;
+ 	crcs_enabled = 0;
++	finobt = 0;
+ 	memset(&fsx, 0, sizeof(fsx));
+ 
+ 	memset(&xi, 0, sizeof(xi));
+@@ -1486,6 +1509,14 @@ _("cannot specify both crc and ftype\n"));
+ 						usage();
+ 					}
+ 					break;
++				case M_FINOBT:
++					if (!value || *value == '\0')
++						reqval('m', mopts, M_CRC);
++					c = atoi(value);
++					if (c < 0 || c > 1)
++						illegal(value, "m finobt");
++					finobt = c;
++					break;
+ 				default:
+ 					unknown('m', value);
+ 				}
+@@ -1827,6 +1858,16 @@ _("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
+ 		}
+ 	}
+ 
++	/*
++	 * The kernel doesn't currently support crc=0,finobt=1 filesystems.
++	 * Catch it here, disable finobt and warn the user.
++	 */
++	if (finobt && !crcs_enabled) {
++		fprintf(stderr,
++_("warning: finobt not supported without CRC support, disabled.\n"));
++		finobt = 0;
++	}
++
+ 	if (nsflag || nlflag) {
+ 		if (dirblocksize < blocksize ||
+ 					dirblocksize > XFS_MAX_BLOCKSIZE) {
+@@ -2413,6 +2454,30 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ 	mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
+ 	mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
+ 
++	/*
++	 * sb_versionnum and finobt flags must be set before we use
++	 * XFS_PREALLOC_BLOCKS().
++	 */
++	sbp->sb_features2 = XFS_SB_VERSION2_MKFS(crcs_enabled, lazy_sb_counters,
++					attrversion == 2, !projid16bit, 0,
++					(!crcs_enabled && dirftype));
++	sbp->sb_versionnum = XFS_SB_VERSION_MKFS(crcs_enabled, iaflag,
++					dsunit != 0,
++					logversion == 2, attrversion == 1,
++					(sectorsize != BBSIZE ||
++							lsectorsize != BBSIZE),
++					nci, sbp->sb_features2 != 0);
++	/*
++	 * Due to a structure alignment issue, sb_features2 ended up in one
++	 * of two locations, the second "incorrect" location represented by
++	 * the sb_bad_features2 field. To avoid older kernels mounting
++	 * filesystems they shouldn't, set both field to the same value.
++	 */
++	sbp->sb_bad_features2 = sbp->sb_features2;
++
++	if (finobt)
++		sbp->sb_features_ro_compat = XFS_SB_FEAT_RO_COMPAT_FINOBT;
++
+ 	if (loginternal) {
+ 		/*
+ 		 * Readjust the log size to fit within an AG if it was sized
+@@ -2475,7 +2540,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ 		printf(_(
+ 		   "meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n"
+ 		   "         =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
+-		   "         =%-22s crc=%u\n"
++		   "         =%-22s crc=%-8u finobt=%u\n"
+ 		   "data     =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
+ 		   "         =%-22s sunit=%-6u swidth=%u blks\n"
+ 		   "naming   =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
+@@ -2484,7 +2549,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ 		   "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"),
+ 			dfile, isize, (long long)agcount, (long long)agsize,
+ 			"", sectorsize, attrversion, !projid16bit,
+-			"", crcs_enabled,
++			"", crcs_enabled, finobt,
+ 			"", blocksize, (long long)dblocks, imaxpct,
+ 			"", dsunit, dswidth,
+ 			dirversion, dirblocksize, nci, dirftype,
+@@ -2553,23 +2618,6 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ 		sbp->sb_logsectsize = 0;
+ 	}
+ 
+-	sbp->sb_features2 = XFS_SB_VERSION2_MKFS(crcs_enabled, lazy_sb_counters,
+-				   attrversion == 2, !projid16bit, 0,
+-				   (!crcs_enabled && dirftype));
+-	sbp->sb_versionnum = XFS_SB_VERSION_MKFS(crcs_enabled, iaflag,
+-					dsunit != 0,
+-					logversion == 2, attrversion == 1,
+-					(sectorsize != BBSIZE ||
+-							lsectorsize != BBSIZE),
+-					nci, sbp->sb_features2 != 0);
+-	/*
+-	 * Due to a structure alignment issue, sb_features2 ended up in one
+-	 * of two locations, the second "incorrect" location represented by
+-	 * the sb_bad_features2 field. To avoid older kernels mounting
+-	 * filesystems they shouldn't, set both field to the same value.
+-	 */
+-	sbp->sb_bad_features2 = sbp->sb_features2;
+-
+ 	if (force_overwrite)
+ 		zero_old_xfs_structures(&xi, sbp);
+ 
+@@ -2726,6 +2774,10 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ 		agi->agi_count = 0;
+ 		agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
+ 		agi->agi_level = cpu_to_be32(1);
++		if (finobt) {
++			agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
++			agi->agi_free_level = cpu_to_be32(1);
++		}
+ 		agi->agi_freecount = 0;
+ 		agi->agi_newino = cpu_to_be32(NULLAGINO);
+ 		agi->agi_dirino = cpu_to_be32(NULLAGINO);
+@@ -2851,6 +2903,26 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ 			xfs_btree_init_block(mp, buf, XFS_IBT_MAGIC, 0, 0,
+ 						agno, 0);
+ 		libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
++
++		/*
++		 * Free INO btree root block
++		 */
++		if (!finobt)
++			continue;
++
++		buf = libxfs_getbuf(mp->m_ddev_targp,
++				XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
++				bsize);
++		buf->b_ops = &xfs_inobt_buf_ops;
++		block = XFS_BUF_TO_BLOCK(buf);
++		memset(block, 0, blocksize);
++		if (xfs_sb_version_hascrc(&mp->m_sb))
++			xfs_btree_init_block(mp, buf, XFS_FIBT_CRC_MAGIC, 0, 0,
++						agno, XFS_BTREE_CRC_BLOCKS);
++		else
++			xfs_btree_init_block(mp, buf, XFS_FIBT_MAGIC, 0, 0,
++						agno, 0);
++		libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
+ 	}
+ 
+ 	/*
+@@ -3087,7 +3159,7 @@ usage( void )
+ {
+ 	fprintf(stderr, _("Usage: %s\n\
+ /* blocksize */		[-b log=n|size=num]\n\
+-/* metadata */		[-m crc=[0|1]\n\
++/* metadata */		[-m crc=0|1,finobt=0|1]\n\
+ /* data subvol */	[-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
+ 			    (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
+ 			    sectlog=n|sectsize=num\n\
+diff --git a/po/pl.po b/po/pl.po
+index ebd1884..80a09a8 100644
+--- a/po/pl.po
++++ b/po/pl.po
+@@ -1,13 +1,13 @@
+ # Polish translation for xfsprogs.
+ # This file is distributed under the same license as the xfsprogs package.
+-# Jakub Bogusz <qboosh at pld-linux.org>, 2006-2012.
++# Jakub Bogusz <qboosh at pld-linux.org>, 2006-2014.
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: xfsprogs 3.1.8\n"
++"Project-Id-Version: xfsprogs 3.2.0\n"
+ "Report-Msgid-Bugs-To: \n"
+-"POT-Creation-Date: 2012-03-04 06:24+0100\n"
+-"PO-Revision-Date: 2012-03-04 07:30+0100\n"
++"POT-Creation-Date: 2014-05-21 18:34+0200\n"
++"PO-Revision-Date: 2014-05-21 18:41+0200\n"
+ "Last-Translator: Jakub Bogusz <qboosh at pld-linux.org>\n"
+ "Language-Team: Polish <translation-team-pl at lists.sourceforge.net>\n"
+ "Language: pl\n"
+@@ -15,6611 +15,6890 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:30
++#: .././copy/xfs_copy.c:102
+ #, c-format
+-msgid "%s [-e extsize] [-p] source target\n"
+-msgstr "%s [-e rozm_fragmentu] [-p] źródło cel\n"
++msgid "Check logfile \"%s\" for more details\n"
++msgstr "Więcej szczegółów w pliku logu \"%s\"\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:55 .././repair/xfs_repair.c:317 .././quota/init.c:131
+-#: .././mkfs/xfs_mkfs.c:1623 .././logprint/logprint.c:196 .././io/init.c:183
+-#: .././growfs/xfs_growfs.c:182 .././fsr/xfs_fsr.c:302
+-#: .././estimate/xfs_estimate.c:141 .././db/init.c:93 .././copy/xfs_copy.c:543
++#: .././copy/xfs_copy.c:108
+ #, c-format
+-msgid "%s version %s\n"
+-msgstr "%s wersja %s\n"
++msgid "%s:  could not write to logfile \"%s\".\n"
++msgstr "%s: nie udało się zapisać pliku logu \"%s\".\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:69
++#: .././copy/xfs_copy.c:111
+ #, c-format
+-msgid "%s: must specify files to copy\n"
+-msgstr "%s: trzeba podać pliki do skopiowania\n"
++msgid "Aborting XFS copy -- logfile error -- reason: %s\n"
++msgstr "Przerwano XFS copy - błąd pliku logu - przyczyna: %s\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:84
+-#, c-format
+-msgid "%s: stat64 of %s failed\n"
+-msgstr "%s: stat64 na %s nie powiodło się\n"
++#: .././copy/xfs_copy.c:126 .././copy/xfs_copy.c:286 .././copy/xfs_copy.c:566
++#: .././copy/xfs_copy.c:573
++msgid "Aborting XFS copy - reason"
++msgstr "Przerwano XFS copy - przyczyna"
+ 
+-#: .././rtcp/xfs_rtcp.c:91
+-#, c-format
+-msgid "%s: final argument is not directory\n"
+-msgstr "%s: ostatni argument nie jest katalogiem\n"
++#: .././copy/xfs_copy.c:140
++msgid "THE FOLLOWING COPIES FAILED TO COMPLETE\n"
++msgstr "NASTĘPUJĄCYCH KOPII NIE UDAŁO SIĘ UKOŃCZYĆ\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:138
+-#, c-format
+-msgid "%s: failed stat64 on %s: %s\n"
+-msgstr "%s: nie udało się wykonać stat64 na %s: %s\n"
++#: .././copy/xfs_copy.c:144
++msgid "write error"
++msgstr "błąd zapisu"
+ 
+-#: .././rtcp/xfs_rtcp.c:159
+-#, c-format
+-msgid "%s: %s filesystem has no realtime partition\n"
+-msgstr "%s: system plików %s nie ma partycji realtime\n"
++#: .././copy/xfs_copy.c:146
++msgid "lseek64 error"
++msgstr "błąd lseek64"
+ 
+-#: .././rtcp/xfs_rtcp.c:180 .././rtcp/xfs_rtcp.c:208
++#: .././copy/xfs_copy.c:147
+ #, c-format
+-msgid "%s: open of %s failed: %s\n"
+-msgstr "%s: otwarcie %s nie powiodło się: %s\n"
++msgid " at offset %lld\n"
++msgstr " pod offsetem %lld\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:197
++#: .././copy/xfs_copy.c:151
+ #, c-format
+-msgid "%s: set attributes on %s failed: %s\n"
+-msgstr "%s: ustawienie atrybutów dla %s nie powiodło się: %s\n"
++msgid "All copies completed.\n"
++msgstr "Wszystkie kopie ukończone.\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:215
++#: .././copy/xfs_copy.c:154
+ #, c-format
+-msgid "%s: get attributes of %s failed: %s\n"
+-msgstr "%s: pobranie atrybutów %s nie powiodło się: %s\n"
++msgid "See \"%s\" for more details.\n"
++msgstr "Więcej szczegółów w \"%s\".\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:225 .././rtcp/xfs_rtcp.c:260
++#: .././copy/xfs_copy.c:255
+ #, c-format
+-msgid "%s: %s is not a realtime file.\n"
+-msgstr "%s: %s nie jest plikiem realtime.\n"
++msgid "%s:  write error on target %d \"%s\" at offset %lld\n"
++msgstr "%s: błąd zapisu przy celu %d \"%s\" pod offsetem %lld\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:234
++#: .././copy/xfs_copy.c:260
+ #, c-format
+-msgid "%s: %s file extent size is %d, instead of %d.\n"
+-msgstr "%s: plik %s ma rozmiar ekstentu %d zamiast %d.\n"
++msgid "%s:  lseek64 error on target %d \"%s\" at offset %lld\n"
++msgstr "%s: błąd lseek64 przy celu %d \"%s\" pod offsetem %lld\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:246 .././rtcp/xfs_rtcp.c:269
++#: .././copy/xfs_copy.c:266
+ #, c-format
+-msgid "%s: open of %s source failed: %s\n"
+-msgstr "%s: otwarcie źródła %s nie powiodło się: %s\n"
++msgid "Aborting target %d - reason"
++msgstr "Przerywano zapis celu %d - przyczyna"
+ 
+-#: .././rtcp/xfs_rtcp.c:283
+-#, c-format
+-msgid "%s: couldn't get direct I/O information: %s\n"
+-msgstr "%s: nie udało się uzyskać informacji o bezpośrednim we/wy: %s\n"
++#: .././copy/xfs_copy.c:270
++msgid "Aborting XFS copy - no more targets.\n"
++msgstr "Przerwano XFS copy - nie ma więcej celów.\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:293
++#: .././copy/xfs_copy.c:281
+ #, c-format
+-msgid "%s: extent size %d not a multiple of %d.\n"
+-msgstr "%s: rozmiar ekstentu %d nie jest wielokrotnością %d.\n"
++msgid "%s:  thread %d died unexpectedly, target \"%s\" incomplete\n"
++msgstr "%s: wątek %d zmarł nieoczekiwanie, cel \"%s\" niekompletny\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:307
++#: .././copy/xfs_copy.c:283
+ #, c-format
+-msgid "The size of %s is not a multiple of %d.\n"
+-msgstr "Rozmiar %s nie jest wielokrotnością %d.\n"
++msgid "%s:  offset was probably %lld\n"
++msgstr "%s: offset prawdopodobnie %lld\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:310
++#: .././copy/xfs_copy.c:294
+ #, c-format
+-msgid "%s will be padded to %lld bytes.\n"
+-msgstr "%s: zostanie dopełniony do %lld bajtów.\n"
++msgid "%s: Unknown child died (should never happen!)\n"
++msgstr "%s: Nieznany potomek zmarł (nie powinno się zdarzyć!)\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:316
++#: .././copy/xfs_copy.c:304
+ #, c-format
+-msgid "Use the -p option to pad %s to a size which is a multiple of %d bytes.\n"
+-msgstr "Można użyć opcji -p do dopełnienia %s do rozmiaru będącego wielokrotnością %d bajtów.\n"
++msgid "Usage: %s [-bdV] [-L logfile] source target [target ...]\n"
++msgstr "Składnia: %s [-bdV] [-L plik_logu] źródło cel [cel ...]\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:358
++#: .././copy/xfs_copy.c:386
+ #, c-format
+-msgid "%s: write error: %s\n"
+-msgstr "%s: błąd zapisu: %s\n"
++msgid "%s:  lseek64 failure at offset %lld\n"
++msgstr "%s: niepowodzenie lseek64 pod offsetem %lld\n"
+ 
+-#: .././rtcp/xfs_rtcp.c:386
++#: .././copy/xfs_copy.c:401
+ #, c-format
+-msgid "%s: could not open %s: %s\n"
+-msgstr "%s: nie udało się otworzyć %s: %s\n"
++msgid "assert error:  buf->length = %d, buf->size = %d\n"
++msgstr "błąd zapewnienia: buf->length = %d, buf->size = %d\n"
+ 
+-#: .././repair/xfs_repair.c:81
++#: .././copy/xfs_copy.c:408
+ #, c-format
+-msgid ""
+-"Usage: %s [options] device\n"
+-"\n"
+-"Options:\n"
+-"  -f           The device is a file\n"
+-"  -L           Force log zeroing. Do this as a last resort.\n"
+-"  -l logdev    Specifies the device where the external log resides.\n"
+-"  -m maxmem    Maximum amount of memory to be used in megabytes.\n"
+-"  -n           No modify mode, just checks the filesystem for damage.\n"
+-"  -P           Disables prefetching.\n"
+-"  -r rtdev     Specifies the device where the realtime section resides.\n"
+-"  -v           Verbose output.\n"
+-"  -c subopts   Change filesystem parameters - use xfs_admin.\n"
+-"  -o subopts   Override default behaviour, refer to man page.\n"
+-"  -t interval  Reporting interval in minutes.\n"
+-"  -d           Repair dangerously.\n"
+-"  -V           Reports version and exits.\n"
+-msgstr ""
+-"Składnia: %s [opcje] urządzenie\n"
+-"\n"
+-"Opcje:\n"
+-"  -f           Urządzenie jest plikiem\n"
+-"  -L           Wymuszenie wyzerowania logu. Wykonywać tylko w ostateczności.\n"
+-"  -l urz_logu  Określenie urządzenia z zewnętrznym logiem.\n"
+-"  -m maks_pam  Maksymalna ilość pamięci do użycia w megabajtach.\n"
+-"  -n           Tryb bez modyfikacji, tylko sprawdzenie systemu plików.\n"
+-"  -P           Wyłączenie prefetch.\n"
+-"  -r urz_rt    Określenie urządzenia z sekcją realtime.\n"
+-"  -v           Szczegółowe wyjście.\n"
+-"  -c podopcje  Zmiana parametrów systemu plików przy użyciu xfs_admina.\n"
+-"  -o podopcje  Zmiana domyślnego zachowania, więcej na stronie manuala.\n"
+-"  -t czas      Okres informowania o postępach w minutach.\n"
+-"  -d           Naprawianie w sposób niebezpieczny.\n"
+-"  -V           Wypisanie informacji o wersji i zakończenie.\n"
+-
+-#: .././repair/xfs_repair.c:107
+-msgid "no error"
+-msgstr "brak błędu"
+-
+-#: .././repair/xfs_repair.c:108
+-msgid "bad magic number"
+-msgstr "błędna liczba magiczna"
+-
+-#: .././repair/xfs_repair.c:109
+-msgid "bad blocksize field"
+-msgstr "błędne pole blocksize"
+-
+-#: .././repair/xfs_repair.c:110
+-msgid "bad blocksize log field"
+-msgstr "błędne pole logu blocksize"
+-
+-#: .././repair/xfs_repair.c:111
+-msgid "bad or unsupported version"
+-msgstr "błędna lub nie obsługiwana wersja"
+-
+-#: .././repair/xfs_repair.c:113
+-msgid "filesystem mkfs-in-progress bit set"
+-msgstr "ustawiony bit mkfs-in-progress systemu plików"
++msgid "%s:  read failure at offset %lld\n"
++msgstr "%s: błąd odczytu pod offsetem %lld\n"
+ 
+-#: .././repair/xfs_repair.c:115
+-msgid "inconsistent filesystem geometry information"
+-msgstr "niespójne informacje o geometrii systemu plików"
++#: .././copy/xfs_copy.c:438
++msgid "ag header buffer invalid!\n"
++msgstr "błędny bufor nagłówka ag!\n"
+ 
+-#: .././repair/xfs_repair.c:117
+-msgid "bad inode size or inconsistent with number of inodes/block"
+-msgstr "błędny rozmiar i-węzła lub niespójność z liczbą i-węzłów/blok"
++#: .././copy/xfs_copy.c:546 .././db/init.c:94 .././estimate/xfs_estimate.c:144
++#: .././fsr/xfs_fsr.c:300 .././growfs/xfs_growfs.c:180 .././io/init.c:190
++#: .././logprint/logprint.c:203 .././mkfs/xfs_mkfs.c:1672
++#: .././quota/init.c:131 .././repair/xfs_repair.c:319 .././rtcp/xfs_rtcp.c:55
++#, c-format
++msgid "%s version %s\n"
++msgstr "%s wersja %s\n"
+ 
+-#: .././repair/xfs_repair.c:118
+-msgid "bad sector size"
+-msgstr "błędny rozmiar sektora"
++#: .././copy/xfs_copy.c:564
++#, c-format
++msgid "%s: couldn't open log file \"%s\"\n"
++msgstr "%s: nie udało się otworzyć pliku logu \"%s\"\n"
+ 
+-#: .././repair/xfs_repair.c:120
+-msgid "AGF geometry info conflicts with filesystem geometry"
+-msgstr "informacje o geometrii AGF są w konflikcie z geometrią systemu plików"
++#: .././copy/xfs_copy.c:571
++#, c-format
++msgid "%s: couldn't set up logfile stream\n"
++msgstr "%s: nie udało się ustanowić strumienia pliku logu\n"
+ 
+-#: .././repair/xfs_repair.c:122
+-msgid "AGI geometry info conflicts with filesystem geometry"
+-msgstr "informacje o geometrii AGI są w konflikcie z geometrią systemu plików"
++#: .././copy/xfs_copy.c:583
++msgid "Couldn't allocate target array\n"
++msgstr "Nie udało się przydzielić tablicy celów\n"
+ 
+-#: .././repair/xfs_repair.c:124
+-msgid "AG superblock geometry info conflicts with filesystem geometry"
+-msgstr "informacje o geometrii superbloku AG są w konflikcie z geometrią systemu plików"
++#: .././copy/xfs_copy.c:598
++#, c-format
++msgid "%s: couldn't register atexit function.\n"
++msgstr "%s: nie udało się zarejestrować funkcji atexit.\n"
+ 
+-#: .././repair/xfs_repair.c:125
+-msgid "attempted to perform I/O beyond EOF"
+-msgstr "próbowano wykonać operację we/wy poza końcem pliku"
++#: .././copy/xfs_copy.c:607
++#, c-format
++msgid "%s:  couldn't open source \"%s\"\n"
++msgstr "%s: nie udało się otworzyć źródła \"%s\"\n"
+ 
+-#: .././repair/xfs_repair.c:127
+-msgid "inconsistent filesystem geometry in realtime filesystem component"
+-msgstr "niespójna geometria systemu plików w składniku realtime"
++#: .././copy/xfs_copy.c:613
++#, c-format
++msgid "%s:  couldn't stat source \"%s\"\n"
++msgstr "%s: nie udało się wykonać stat na źródle \"%s\"\n"
+ 
+-#: .././repair/xfs_repair.c:129
+-msgid "maximum indicated percentage of inodes > 100%"
+-msgstr "określono maksymalny procent i-węzłów > 100%"
++#: .././copy/xfs_copy.c:623
++#, c-format
++msgid "%s: Cannot set direct I/O flag on \"%s\".\n"
++msgstr "%s: Nie można ustawić flagi bezpośredniego we/wy na \"%s\".\n"
+ 
+-#: .././repair/xfs_repair.c:131
+-msgid "inconsistent inode alignment value"
+-msgstr "niespójna wartość wyrównania i-węzła"
++#: .././copy/xfs_copy.c:628
++#, c-format
++msgid "%s: xfsctl on file \"%s\" failed.\n"
++msgstr "%s: xfsctl na pliku \"%s\" nie powiodło się.\n"
+ 
+-#: .././repair/xfs_repair.c:133
+-msgid "not enough secondary superblocks with matching geometry"
+-msgstr "za mało zapasowych superbloków o pasującej geometrii"
++#: .././copy/xfs_copy.c:651
++#, c-format
++msgid "%s:  Warning -- a filesystem is mounted on the source device.\n"
++msgstr "%s: Uwaga - system plików jest podmontowany na urządzeniu źródłowym.\n"
+ 
+-#: .././repair/xfs_repair.c:135
+-msgid "bad stripe unit in superblock"
+-msgstr "błędna jednostka pasa w superbloku"
++#: .././copy/xfs_copy.c:654
++msgid "\t\tGenerated copies may be corrupt unless the source is\n"
++msgstr "\t\tWygenerowane kopie mogą być uszkodzone o ile źródło nie jest\n"
+ 
+-#: .././repair/xfs_repair.c:137
+-msgid "bad stripe width in superblock"
+-msgstr "błędna szerokość pasa w superbloku"
++#: .././copy/xfs_copy.c:656
++msgid "\t\tunmounted or mounted read-only.  Copy proceeding...\n"
++msgstr "\t\todmontowane lub podmontowane tylko do odczytu. Kopiowanie w trakcie...\n"
+ 
+-#: .././repair/xfs_repair.c:139
+-msgid "bad shared version number in superblock"
+-msgstr "błędny numer wersji współdzielenia w superbloku"
++#: .././copy/xfs_copy.c:673
++#, c-format
++msgid ""
++"%s: couldn't initialize XFS library\n"
++"%s: Aborting.\n"
++msgstr ""
++"%s: nie udało się zainicjować biblioteki XFS\n"
++"%s: Przerwano.\n"
+ 
+-#: .././repair/xfs_repair.c:144
++#: .././copy/xfs_copy.c:693
+ #, c-format
+-msgid "bad error code - %d\n"
+-msgstr "błędny kod błędu - %d\n"
++msgid "%s: Cannot yet copy V5 fs without '-d'\n"
++msgstr "%s: Nie można jeszcze kopiować systemu plików V5 bez '-d'\n"
+ 
+-#: .././repair/xfs_repair.c:152
++#: .././copy/xfs_copy.c:699
+ #, c-format
+-msgid "-%c %s option cannot have a value\n"
+-msgstr "opcja -%c %s nie przyjmuje wartości\n"
++msgid ""
++"%s: %s filesystem failed to initialize\n"
++"%s: Aborting.\n"
++msgstr ""
++"%s: Nie powiodła się inicjalizacja systemu plików %s\n"
++"%s: Przerwano.\n"
+ 
+-#: .././repair/xfs_repair.c:162 .././mkfs/xfs_mkfs.c:2801
++#: .././copy/xfs_copy.c:703
+ #, c-format
+-msgid "option respecified\n"
+-msgstr "ponownie podana opcja\n"
++msgid ""
++"%s %s filesystem failed to initialize\n"
++"%s: Aborting.\n"
++msgstr ""
++"%s: Nie powiodła się inicjalizacja systemu plików %s\n"
++"%s: Przerwano.\n"
+ 
+-#: .././repair/xfs_repair.c:169 .././mkfs/xfs_mkfs.c:2810
++#: .././copy/xfs_copy.c:707
+ #, c-format
+-msgid "unknown option -%c %s\n"
+-msgstr "nieznana opcja -%c %s\n"
+-
+-#: .././repair/xfs_repair.c:248
+-msgid "-o bhash option cannot be used with -m option\n"
+-msgstr "opcja -o bhash nie może być użyta wraz z opcją -m\n"
+-
+-#: .././repair/xfs_repair.c:300
+-msgid "-m option cannot be used with -o bhash option\n"
+-msgstr "opcja -m nie może być użyta wraz z opcją -o bhash\n"
++msgid ""
++"%s: %s has an external log.\n"
++"%s: Aborting.\n"
++msgstr ""
++"%s: %s ma zewnętrzny log.\n"
++"%s: Przerwano.\n"
+ 
+-#: .././repair/xfs_repair.c:342
++#: .././copy/xfs_copy.c:711
+ #, c-format
+ msgid ""
+-"\n"
+-"fatal error -- "
++"%s: %s has a real-time section.\n"
++"%s: Aborting.\n"
+ msgstr ""
+-"\n"
+-"błąd krytyczny - "
++"%s: %s ma sekcję real-time.\n"
++"%s: Przerwano.\n"
+ 
+-#: .././repair/xfs_repair.c:454
+-#, c-format
+-msgid "sb root inode value %<PRIu64> %sinconsistent with calculated value %u\n"
+-msgstr "wartość i-węzła głównego superbloku %<PRIu64> %sniespójna z obliczoną wartością %u\n"
++#: .././copy/xfs_copy.c:736
++msgid ""
++"Error:  filesystem block size is smaller than the disk sectorsize.\n"
++"Aborting XFS copy now.\n"
++msgstr ""
++"Błąd: rozmiar bloku systemu plików jest mniejszy niż rozmiar sektora dysku.\n"
++"Przerwano XFS copy.\n"
+ 
+-#: .././repair/xfs_repair.c:461
++#: .././copy/xfs_copy.c:757
+ #, c-format
+-msgid "resetting superblock root inode pointer to %u\n"
+-msgstr "przestawiono wskaźnik i-węzła głównego superbloku na %u\n"
++msgid "Creating file %s\n"
++msgstr "Tworzenie pliku %s\n"
+ 
+-#: .././repair/xfs_repair.c:465
++#: .././copy/xfs_copy.c:775
+ #, c-format
+-msgid "would reset superblock root inode pointer to %u\n"
+-msgstr "wskaźnik i-węzła głównego superbloku zostałby przestawiony na %u\n"
++msgid ""
++"%s:  a filesystem is mounted on target device \"%s\".\n"
++"%s cannot copy to mounted filesystems.  Aborting\n"
++msgstr ""
++"%s: na urządzeniu docelowym \"%s\" jest podmontowany system plików.\n"
++"%s nie może kopiować na podmontowane systemy plików. Przerwano.\n"
+ 
+-#: .././repair/xfs_repair.c:477
++#: .././copy/xfs_copy.c:786
+ #, c-format
+-msgid "sb realtime bitmap inode %<PRIu64> %sinconsistent with calculated value %u\n"
+-msgstr "i-węzeł bitmapy realtime superbloku %<PRIu64> %sniespójny z obliczoną wartością %u\n"
++msgid "%s:  couldn't open target \"%s\"\n"
++msgstr "%s: nie udało się otworzyć celu \"%s\"\n"
+ 
+-#: .././repair/xfs_repair.c:484
++#: .././copy/xfs_copy.c:796
+ #, c-format
+-msgid "resetting superblock realtime bitmap ino pointer to %u\n"
+-msgstr "przestawiono wskaźnik i-węzła bitmapy realtime superbloku na %u\n"
++msgid "%s:  cannot grow data section.\n"
++msgstr "%s: nie można powiększyć sekcji danych.\n"
+ 
+-#: .././repair/xfs_repair.c:488
++#: .././copy/xfs_copy.c:804
+ #, c-format
+-msgid "would reset superblock realtime bitmap ino pointer to %u\n"
+-msgstr "wskaźnik i-węzła bitmapy realtime superbloku zostałby przestawiony na %u\n"
++msgid "%s:  xfsctl on \"%s\" failed.\n"
++msgstr "%s: xfsctl na \"%s\" nie powiodło się.\n"
+ 
+-#: .././repair/xfs_repair.c:500
++#: .././copy/xfs_copy.c:823
+ #, c-format
+-msgid "sb realtime summary inode %<PRIu64> %sinconsistent with calculated value %u\n"
+-msgstr "i-węzeł opisu realtime superbloku %<PRIu64> %sniespójny z obliczoną wartością %u\n"
++msgid "%s:  failed to write last block\n"
++msgstr "%s: nie udało się zapisać ostatniego bloku\n"
+ 
+-#: .././repair/xfs_repair.c:507
++#: .././copy/xfs_copy.c:825
+ #, c-format
+-msgid "resetting superblock realtime summary ino pointer to %u\n"
+-msgstr "przestawiono wskaźnik i-węzła opisu realtime superbloku na %u\n"
++msgid "\tIs target \"%s\" too small?\n"
++msgstr "\tCzy cel \"%s\" jest zbyt mały?\n"
+ 
+-#: .././repair/xfs_repair.c:511
+-#, c-format
+-msgid "would reset superblock realtime summary ino pointer to %u\n"
+-msgstr "wskaźnik i-węzła opisu realtime superbloku zostałby przestawiony na %u\n"
++#: .././copy/xfs_copy.c:835
++msgid "Couldn't initialize global thread mask\n"
++msgstr "Nie udało się zainicjować globalnej maski wątków\n"
+ 
+-#: .././repair/xfs_repair.c:554
+-msgid ""
+-"Primary superblock would have been modified.\n"
+-"Cannot proceed further in no_modify mode.\n"
+-"Exiting now.\n"
+-msgstr ""
+-"Główny superblok zostałby zmodyfikowany.\n"
+-"Nie można kontynuować w trybie bez modyfikacji.\n"
+-"Zakończono.\n"
++#: .././copy/xfs_copy.c:842
++msgid "Error initializing wbuf 0\n"
++msgstr "Błąd inicjalizacji wbuf 0\n"
+ 
+-#: .././repair/xfs_repair.c:577
+-msgid ""
+-"Cannot get host filesystem geometry.\n"
+-"Repair may fail if there is a sector size mismatch between\n"
+-"the image and the host filesystem.\n"
+-msgstr ""
+-"Nie można pobrać geometrii systemu plików hosta.\n"
+-"Naprawienie może się nie powieść, jeśli istnieje niespójność rozmiaru\n"
+-"sektora między obrazem a systemem plików hosta.\n"
++#: .././copy/xfs_copy.c:850
++msgid "Error initializing btree buf 1\n"
++msgstr "Błąd inicjalizacji btree buf 1\n"
+ 
+-#: .././repair/xfs_repair.c:589
+-msgid ""
+-"Sector size on host filesystem larger than image sector size.\n"
+-"Cannot turn off direct IO, so exiting.\n"
+-msgstr ""
+-"Rozmiar sektora na systemie plików hosta większy niż rozmiar sektora obrazu.\n"
+-"Nie można wyłączyć bezpośredniego we/wy - zakończono działanie.\n"
++#: .././copy/xfs_copy.c:855
++msgid "Error creating first semaphore.\n"
++msgstr "Błąd tworzenia pierwszego semafora.\n"
+ 
+-#: .././repair/xfs_repair.c:599
+-#, c-format
+-msgid "%s: cannot repair this filesystem.  Sorry.\n"
+-msgstr "%s: niestety nie można naprawić tego systemu plików.\n"
++#: .././copy/xfs_copy.c:870
++msgid "Couldn't malloc space for thread args\n"
++msgstr "Nie udało się przydzielić miejsca na argumenty wątku\n"
+ 
+-#: .././repair/xfs_repair.c:624
++#: .././copy/xfs_copy.c:882
+ #, c-format
+-msgid "        - reporting progress in intervals of %s\n"
+-msgstr "        - informowanie o postępie w odstępach %s\n"
++msgid "Error creating thread mutex %d\n"
++msgstr "Błąd podczas tworzenia sekcji krytycznej %d wątku\n"
+ 
+-#: .././repair/xfs_repair.c:671
++#: .././copy/xfs_copy.c:899
+ #, c-format
+-msgid "        - max_mem = %lu, icount = %<PRIu64>, imem = %<PRIu64>, dblock = %<PRIu64>, dmem = %<PRIu64>\n"
+-msgstr "        - max_mem = %lu, icount = %<PRIu64>, imem = %<PRIu64>, dblock = %<PRIu64>, dmem = %<PRIu64>\n"
++msgid "Error creating thread for target %d\n"
++msgstr "Błąd podczas tworzenia wątku dla celu %d\n"
+ 
+-#: .././repair/xfs_repair.c:684
++#: .././copy/xfs_copy.c:953
+ #, c-format
+-msgid ""
+-"Required memory for repair is greater that the maximum specified\n"
+-"with the -m option. Please increase it to at least %lu.\n"
+-msgstr ""
+-"Pamięć wymagana do naprawy przekracza maksimum określone opcją -m.\n"
+-"Proszę ją zwiększyć do co najmniej %lu.\n"
++msgid "Error: current level %d >= btree levels %d\n"
++msgstr "Błąd: bieżący poziom %d >= poziomów b-drzewa %d\n"
+ 
+-#: .././repair/xfs_repair.c:689
++#: .././copy/xfs_copy.c:972
+ #, c-format
++msgid "Bad btree magic 0x%x\n"
++msgstr "Niewłaściwa liczba magiczna b-drzewa 0x%x\n"
++
++#: .././copy/xfs_copy.c:999
++msgid "WARNING:  source filesystem inconsistent.\n"
++msgstr "UWAGA: źródłowy system plików niespójny.\n"
++
++#: .././copy/xfs_copy.c:1001
++msgid "  A leaf btree rec isn't a leaf.  Aborting now.\n"
++msgstr " Liść rekordu b-drzewa nie jest liściem. Przerwano.\n"
++
++#: .././db/addr.c:35
++msgid "[field-expression]"
++msgstr "[wyrażenie-pól]"
++
++#: .././db/addr.c:36
++msgid "set current address"
++msgstr "ustawienie bieżącego adresu"
++
++#: .././db/addr.c:42
+ msgid ""
+-"Not enough RAM available for repair to enable prefetching.\n"
+-"This will be _slow_.\n"
+-"You need at least %luMB RAM to run with prefetching enabled.\n"
++"\n"
++" 'addr' uses the given field to set the filesystem address and type\n"
++"\n"
++" Examples:\n"
++"\n"
++" sb\n"
++" a rootino - set the type to inode and set position to the root inode\n"
++" a u.bmx[0].startblock (for inode with blockmap)\n"
++"\n"
+ msgstr ""
+-"Zbyt mało dostępnej pamięci RAM, żeby naprawiać z włączonym prefetch.\n"
+-"To będzie _wolne_.\n"
+-"Do włączenia prefetch potrzeba przynajmniej %luMB RAM.\n"
+-
+-#: .././repair/xfs_repair.c:707
+-#, c-format
+-msgid "        - block cache size set to %d entries\n"
+-msgstr "        - rozmiar bufora bloku ustawiony na %d wpisów\n"
++"\n"
++" 'addr' wykorzystuje podane pole do ustawienia adresu w systemie plików i typu\n"
++"\n"
++" Przykłady:\n"
++"\n"
++" sb\n"
++" a rootino - ustawienie typu na i-węzeł i pozycji na i-węzeł główny\n"
++" a u.bmx[0].startblock (dla i-węzła z mapą bloków)\n"
++"\n"
+ 
+-#: .././repair/xfs_repair.c:736
+-msgid "Found unsupported filesystem features.  Exiting now.\n"
+-msgstr "Znaleziono nie obsługiwane cechy systemu plików. Zakończono.\n"
++#: .././db/addr.c:72 .././db/attrset.c:86 .././db/attrset.c:189
++#: .././db/print.c:74 .././db/type.c:142 .././db/write.c:101
++msgid "no current type\n"
++msgstr "brak bieżącego typu\n"
+ 
+-#: .././repair/xfs_repair.c:754
++#: .././db/addr.c:82
+ #, c-format
+-msgid "No modify flag set, skipping phase 5\n"
+-msgstr "Ustawiono flagę braku modyfikacji, pominięto fazę 5\n"
+-
+-#: .././repair/xfs_repair.c:773
+-msgid "Inode allocation btrees are too corrupted, skipping phases 6 and 7\n"
+-msgstr "B-drzewa alokacji i-węzłów są zbyt uszkodzone, pominięto fazy 6 i 7\n"
++msgid "no fields for type %s\n"
++msgstr "brak pól dla typu %s\n"
+ 
+-#: .././repair/xfs_repair.c:779
+-msgid "Warning:  no quota inodes were found.  Quotas disabled.\n"
+-msgstr "Uwaga: nie znaleziono i-węzłów limitów (quot). Limity wyłączone.\n"
++#: .././db/addr.c:94
++msgid "array not allowed for addr command\n"
++msgstr "tablica nie jest dozwolona dla polecenia addr\n"
+ 
+-#: .././repair/xfs_repair.c:782
+-msgid "Warning:  no quota inodes were found.  Quotas would be disabled.\n"
+-msgstr "Uwaga: nie znaleziono i-węzłów limitów (quot). Limity zostałyby wyłączone.\n"
++#: .././db/addr.c:103
++#, c-format
++msgid "no next type for field %s\n"
++msgstr "brak następnego typu dla pola %s\n"
+ 
+-#: .././repair/xfs_repair.c:787
+-msgid "Warning:  quota inodes were cleared.  Quotas disabled.\n"
+-msgstr "Uwaga: i-węzły limitów (quot) były wyczyszczone. Limity wyłączone.\n"
++#: .././db/addr.c:110
++#, c-format
++msgid "no addr function for field %s (type %s)\n"
++msgstr "brak funkcji addr dla pola %s (typu %s)\n"
+ 
+-#: .././repair/xfs_repair.c:790
+-msgid "Warning:  quota inodes would be cleared.  Quotas would be disabled.\n"
+-msgstr "Uwaga: i-węzły limitów (quot) zostałyby wyczyszczone. Limity zostałyby wyłączone.\n"
++#: .././db/agf.c:35 .././db/agfl.c:36 .././db/agi.c:35 .././db/sb.c:42
++msgid "[agno]"
++msgstr "[agno]"
+ 
+-#: .././repair/xfs_repair.c:796
+-msgid ""
+-"Warning:  user quota information was cleared.\n"
+-"User quotas can not be enforced until limit information is recreated.\n"
+-msgstr ""
+-"Uwaga: informacje o limitach użytkowników były wyczyszczone.\n"
+-"Limity użytkowników nie mogą być wymuszone do czasu odtworzenia informacji.\n"
++#: .././db/agf.c:36
++msgid "set address to agf header"
++msgstr "ustawienie adresu na nagłówek agf"
+ 
+-#: .././repair/xfs_repair.c:800
++#: .././db/agf.c:82
+ msgid ""
+-"Warning:  user quota information would be cleared.\n"
+-"User quotas could not be enforced until limit information was recreated.\n"
++"\n"
++" set allocation group free block list\n"
++"\n"
++" Example:\n"
++"\n"
++" agf 2 - move location to AGF in 2nd filesystem allocation group\n"
++"\n"
++" Located in the second sector of each allocation group, the AGF\n"
++" contains the root of two different freespace btrees:\n"
<Skipped 23241 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/xfsprogs.git/commitdiff/3d585810b809dcbcd72815e22177f65e1cec8853



More information about the pld-cvs-commit mailing list