Blame SOURCES/xfsprogs-diff-since-alpha2.patch

0690ef
diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
0690ef
index 9986fbf..9f2f99d 100644
0690ef
--- a/copy/xfs_copy.c
0690ef
+++ b/copy/xfs_copy.c
0690ef
@@ -684,6 +684,16 @@ main(int argc, char **argv)
0690ef
 	sb = &mbuf.m_sb;
0690ef
 	libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
0690ef
 
0690ef
+	/*
0690ef
+	 * For now, V5 superblock filesystems are not supported without -d;
0690ef
+	 * we do not have the infrastructure yet to fix CRCs when a new UUID
0690ef
+	 * is generated.
0690ef
+	 */
0690ef
+	if (xfs_sb_version_hascrc(sb) && !duplicate) {
0690ef
+		do_log(_("%s: Cannot yet copy V5 fs without '-d'\n"), progname);
0690ef
+		exit(1);
0690ef
+	}
0690ef
+
0690ef
 	mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
0690ef
 	if (mp == NULL) {
0690ef
 		do_log(_("%s: %s filesystem failed to initialize\n"
0690ef
@@ -957,7 +967,13 @@ main(int argc, char **argv)
0690ef
 				 ((char *)btree_buf.data +
0690ef
 				  pos - btree_buf.position);
0690ef
 
0690ef
-			ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC);
0690ef
+			if (be32_to_cpu(block->bb_magic) !=
0690ef
+			    (xfs_sb_version_hascrc(&mp->m_sb) ?
0690ef
+			     XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) {
0690ef
+				do_log(_("Bad btree magic 0x%x\n"),
0690ef
+				        be32_to_cpu(block->bb_magic));
0690ef
+				exit(1);
0690ef
+			}
0690ef
 
0690ef
 			if (be16_to_cpu(block->bb_level) == 0)
0690ef
 				break;
0690ef
diff --git a/db/attr.c b/db/attr.c
0690ef
index 740d564..caa154e 100644
0690ef
--- a/db/attr.c
0690ef
+++ b/db/attr.c
0690ef
@@ -170,7 +170,7 @@ attr3_leaf_entries_count(
0690ef
 	struct xfs_attr3_leafblock *leaf = obj;
0690ef
 
0690ef
 	ASSERT(startoff == 0);
0690ef
-	if (be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_ATTR_LEAF_MAGIC)
0690ef
+	if (be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_ATTR3_LEAF_MAGIC)
0690ef
 		return 0;
0690ef
 	return be16_to_cpu(leaf->hdr.count);
0690ef
 }
0690ef
diff --git a/db/bit.c b/db/bit.c
0690ef
index ca57d31..e8adab3 100644
0690ef
--- a/db/bit.c
0690ef
+++ b/db/bit.c
0690ef
@@ -128,57 +128,41 @@ getbitval(
0690ef
 	return rval;
0690ef
 }
0690ef
 
0690ef
+/*
0690ef
+ * The input data can be 8, 16, 32, and 64 sized numeric values
0690ef
+ * aligned on a byte boundry, or odd sized numbers stored on odd
0690ef
+ * aligned offset (for example the bmbt fields).
0690ef
+ *
0690ef
+ * The input data sent to this routine has been converted to big endian
0690ef
+ * and has been adjusted in the array so that the first input bit is to
0690ef
+ * be written in the first bit in the output.
0690ef
+ *
0690ef
+ * If the field length and the output buffer are byte aligned, then use
0690ef
+ * memcpy from the input to the output, but if either entries are not byte
0690ef
+ * aligned, then loop over the entire bit range reading the input value
0690ef
+ * and set/clear the matching bit in the output.
0690ef
+ *
0690ef
+ * example when ibuf is not multiple of a byte in length:
0690ef
+ *
0690ef
+ * ibuf:	| BBBBBBBB | bbbxxxxx |
0690ef
+ *		  \\\\\\\\--\\\\
0690ef
+ * obuf+bitoff:	| xBBBBBBB | Bbbbxxxx |
0690ef
+ *
0690ef
+ */
0690ef
 void
0690ef
 setbitval(
0690ef
-	void *obuf,      /* buffer to write into */
0690ef
-	int bitoff,      /* bit offset of where to write */
0690ef
-	int nbits,       /* number of bits to write */
0690ef
-	void *ibuf)      /* source bits */
0690ef
+	void	*obuf,		/* start of buffer to write into */
0690ef
+	int	bitoff,		/* bit offset into the output buffer */
0690ef
+	int	nbits,		/* number of bits to write */
0690ef
+	void	*ibuf)		/* source bits */
0690ef
 {
0690ef
-	char    *in           = (char *)ibuf;
0690ef
-	char    *out          = (char *)obuf;
0690ef
-
0690ef
-	int     bit;
0690ef
-
0690ef
-#if BYTE_ORDER == LITTLE_ENDIAN
0690ef
-	int     big           = 0;
0690ef
-#else
0690ef
-	int     big           = 1;
0690ef
-#endif
0690ef
-
0690ef
-	/* only need to swap LE integers */
0690ef
-	if (big || (nbits!=16 && nbits!=32 && nbits!=64) ) {
0690ef
-		/* We don't have type info, so we can only assume
0690ef
-		 * that 2,4 & 8 byte values are integers. sigh.
0690ef
-		 */
0690ef
-
0690ef
-		/* byte aligned ? */
0690ef
-		if (bitoff%NBBY) {
0690ef
-			/* no - bit copy */
0690ef
-			for (bit=0; bit
0690ef
-				setbit(out, bit+bitoff, getbit(in, bit));
0690ef
-		} else {
0690ef
-			/* yes - byte copy */
0690ef
-			memcpy(out+byteize(bitoff), in, byteize(nbits));
0690ef
-		}
0690ef
-
0690ef
-	} else {
0690ef
-		int     ibit;
0690ef
-		int     obit;
0690ef
-
0690ef
-		/* we need to endian swap this value */
0690ef
-
0690ef
-		out+=byteize(bitoff);
0690ef
-		obit=bitoffs(bitoff);
0690ef
-
0690ef
-		ibit=nbits-NBBY;
0690ef
-
0690ef
-		for (bit=0; bit
0690ef
-			setbit(out, bit+obit, getbit(in, ibit));
0690ef
-			if (ibit%NBBY==NBBY-1)
0690ef
-				ibit-=NBBY*2-1;
0690ef
-			else
0690ef
-				ibit++;
0690ef
-		}
0690ef
-	}
0690ef
+	char	*in = ibuf;
0690ef
+	char	*out = obuf;
0690ef
+	int	bit;
0690ef
+
0690ef
+	if (bitoff % NBBY || nbits % NBBY) {
0690ef
+		for (bit = 0; bit < nbits; bit++)
0690ef
+			setbit(out, bit + bitoff, getbit(in, bit));
0690ef
+	} else
0690ef
+		memcpy(out + byteize(bitoff), in, byteize(nbits));
0690ef
 }
0690ef
diff --git a/db/init.c b/db/init.c
0690ef
index 8f86f45..e7f536a 100644
0690ef
--- a/db/init.c
0690ef
+++ b/db/init.c
0690ef
@@ -140,8 +140,10 @@ init(
0690ef
 	if (sbp->sb_magicnum != XFS_SB_MAGIC) {
0690ef
 		fprintf(stderr, _("%s: %s is not a valid XFS filesystem (unexpected SB magic number 0x%08x)\n"),
0690ef
 			progname, fsdevice, sbp->sb_magicnum);
0690ef
-		if (!force)
0690ef
+		if (!force) {
0690ef
+			fprintf(stderr, _("Use -F to force a read attempt.\n"));
0690ef
 			exit(EXIT_FAILURE);
0690ef
+		}
0690ef
 	}
0690ef
 
0690ef
 	mp = libxfs_mount(&xmount, sbp, x.ddev, x.logdev, x.rtdev,
0690ef
diff --git a/db/io.c b/db/io.c
0690ef
index 123214d..9a787c8 100644
0690ef
--- a/db/io.c
0690ef
+++ b/db/io.c
0690ef
@@ -449,9 +449,7 @@ write_cur_bbs(void)
0690ef
 
0690ef
 
0690ef
 	/* re-read buffer from disk */
0690ef
-	ret = libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp,
0690ef
-				  iocur_top->bbmap->b, iocur_top->bbmap->nmaps,
0690ef
-				  0);
0690ef
+	ret = libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0);
0690ef
 	if (ret != 0)
0690ef
 		dbprintf(_("read error: %s\n"), strerror(ret));
0690ef
 }
0690ef
@@ -523,10 +521,11 @@ set_cur(
0690ef
 	}
0690ef
 
0690ef
 	/*
0690ef
-	 * keep the buffer even if the verifier says it is corrupted.
0690ef
+	 * Keep the buffer even if the verifier says it is corrupted.
0690ef
 	 * We're a diagnostic tool, after all.
0690ef
 	 */
0690ef
-	if (!bp || (bp->b_error && bp->b_error != EFSCORRUPTED))
0690ef
+	if (!bp || (bp->b_error && bp->b_error != EFSCORRUPTED &&
0690ef
+				   bp->b_error != EFSBADCRC))
0690ef
 		return;
0690ef
 	iocur_top->buf = bp->b_addr;
0690ef
 	iocur_top->bp = bp;
0690ef
diff --git a/db/io.h b/db/io.h
0690ef
index 4f24c83..ad39bee 100644
0690ef
--- a/db/io.h
0690ef
+++ b/db/io.h
0690ef
@@ -41,6 +41,7 @@ typedef struct iocur {
0690ef
 	int			ino_crc_ok:1;
0690ef
 	int			ino_buf:1;
0690ef
 	int			dquot_buf:1;
0690ef
+	int			need_crc:1;
0690ef
 } iocur_t;
0690ef
 
0690ef
 #define DB_RING_ADD 1                   /* add to ring on set_cur */
0690ef
@@ -66,6 +67,6 @@ static inline bool
0690ef
 iocur_crc_valid()
0690ef
 {
0690ef
 	return (iocur_top->bp &&
0690ef
-		iocur_top->bp->b_error != EFSCORRUPTED &&
0690ef
+		iocur_top->bp->b_error != EFSBADCRC &&
0690ef
 		(!iocur_top->ino_buf || iocur_top->ino_crc_ok));
0690ef
 }
0690ef
diff --git a/db/metadump.c b/db/metadump.c
0690ef
index 117dc42..09bb85a 100644
0690ef
--- a/db/metadump.c
0690ef
+++ b/db/metadump.c
0690ef
@@ -145,6 +145,8 @@ print_progress(const char *fmt, ...)
0690ef
  * even if the dump is exactly aligned, the last index will be full of
0690ef
  * zeros. If the last index entry is non-zero, the dump is incomplete.
0690ef
  * Correspondingly, the last chunk will have a count < num_indicies.
0690ef
+ *
0690ef
+ * Return 0 for success, -1 for failure.
0690ef
  */
0690ef
 
0690ef
 static int
0690ef
@@ -156,49 +158,88 @@ write_index(void)
0690ef
 	metablock->mb_count = cpu_to_be16(cur_index);
0690ef
 	if (fwrite(metablock, (cur_index + 1) << BBSHIFT, 1, outf) != 1) {
0690ef
 		print_warning("error writing to file: %s", strerror(errno));
0690ef
-		return 0;
0690ef
+		return -errno;
0690ef
 	}
0690ef
 
0690ef
 	memset(block_index, 0, num_indicies * sizeof(__be64));
0690ef
 	cur_index = 0;
0690ef
-	return 1;
0690ef
+	return 0;
0690ef
+}
0690ef
+
0690ef
+/*
0690ef
+ * Return 0 for success, -errno for failure.
0690ef
+ */
0690ef
+static int
0690ef
+write_buf_segment(
0690ef
+	char		*data,
0690ef
+	__int64_t	off,
0690ef
+	int		len)
0690ef
+{
0690ef
+	int		i;
0690ef
+	int		ret;
0690ef
+
0690ef
+	for (i = 0; i < len; i++, off++, data += BBSIZE) {
0690ef
+		block_index[cur_index] = cpu_to_be64(off);
0690ef
+		memcpy(&block_buffer[cur_index << BBSHIFT], data, BBSIZE);
0690ef
+		if (++cur_index == num_indicies) {
0690ef
+			ret = write_index();
0690ef
+			if (ret)
0690ef
+				return -EIO;
0690ef
+		}
0690ef
+	}
0690ef
+	return 0;
0690ef
 }
0690ef
 
0690ef
+/*
0690ef
+ * we want to preserve the state of the metadata in the dump - whether it is
0690ef
+ * intact or corrupt, so even if the buffer has a verifier attached to it we
0690ef
+ * don't want to run it prior to writing the buffer to the metadump image.
0690ef
+ *
0690ef
+ * The only reason for running the verifier is to recalculate the CRCs on a
0690ef
+ * buffer that has been obfuscated. i.e. a buffer than metadump modified itself.
0690ef
+ * In this case, we only run the verifier if the buffer was not corrupt to begin
0690ef
+ * with so that we don't accidentally correct buffers with CRC or errors in them
0690ef
+ * when we are obfuscating them.
0690ef
+ */
0690ef
 static int
0690ef
 write_buf(
0690ef
 	iocur_t		*buf)
0690ef
 {
0690ef
-	char		*data;
0690ef
-	__int64_t	off;
0690ef
+	struct xfs_buf	*bp = buf->bp;
0690ef
 	int		i;
0690ef
+	int		ret;
0690ef
 
0690ef
 	/*
0690ef
 	 * Run the write verifier to recalculate the buffer CRCs and check
0690ef
-	 * we are writing something valid to disk
0690ef
+	 * metadump didn't introduce a new corruption. Warn if the verifier
0690ef
+	 * failed, but still continue to dump it into the output file.
0690ef
 	 */
0690ef
-	if (buf->bp && buf->bp->b_ops) {
0690ef
-		buf->bp->b_error = 0;
0690ef
-		buf->bp->b_ops->verify_write(buf->bp);
0690ef
-		if (buf->bp->b_error) {
0690ef
-			fprintf(stderr,
0690ef
-	_("%s: write verifer failed on bno 0x%llx/0x%x\n"),
0690ef
-				__func__, (long long)buf->bp->b_bn,
0690ef
-				buf->bp->b_bcount);
0690ef
-			return buf->bp->b_error;
0690ef
+	if (buf->need_crc && bp && bp->b_ops && !bp->b_error) {
0690ef
+		bp->b_ops->verify_write(bp);
0690ef
+		if (bp->b_error) {
0690ef
+			print_warning(
0690ef
+				"obfuscation corrupted block at bno 0x%llx/0x%x",
0690ef
+				(long long)bp->b_bn, bp->b_bcount);
0690ef
 		}
0690ef
 	}
0690ef
 
0690ef
-	for (i = 0, off = buf->bb, data = buf->data;
0690ef
-			i < buf->blen;
0690ef
-			i++, off++, data += BBSIZE) {
0690ef
-		block_index[cur_index] = cpu_to_be64(off);
0690ef
-		memcpy(&block_buffer[cur_index << BBSHIFT], data, BBSIZE);
0690ef
-		if (++cur_index == num_indicies) {
0690ef
-			if (!write_index())
0690ef
-				return 0;
0690ef
+	/* handle discontiguous buffers */
0690ef
+	if (!buf->bbmap) {
0690ef
+		ret = write_buf_segment(buf->data, buf->bb, buf->blen);
0690ef
+		if (ret)
0690ef
+			return ret;
0690ef
+	} else {
0690ef
+		int	len = 0;
0690ef
+		for (i = 0; i < buf->bbmap->nmaps; i++) {
0690ef
+			ret = write_buf_segment(buf->data + BBTOB(len),
0690ef
+						buf->bbmap->b[i].bm_bn,
0690ef
+						buf->bbmap->b[i].bm_len);
0690ef
+			if (ret)
0690ef
+				return ret;
0690ef
+			len += buf->bbmap->b[i].bm_len;
0690ef
 		}
0690ef
 	}
0690ef
-	return !seenint();
0690ef
+	return seenint() ? -EINTR : 0;
0690ef
 }
0690ef
 
0690ef
 
0690ef
@@ -227,7 +268,7 @@ scan_btree(
0690ef
 		rval = !stop_on_read_error;
0690ef
 		goto pop_out;
0690ef
 	}
0690ef
-	if (!write_buf(iocur_top))
0690ef
+	if (write_buf(iocur_top))
0690ef
 		goto pop_out;
0690ef
 
0690ef
 	if (!(*func)(iocur_top->data, agno, agbno, level - 1, btype, arg))
0690ef
@@ -974,16 +1015,23 @@ obfuscate_sf_dir(
0690ef
 	}
0690ef
 }
0690ef
 
0690ef
+/*
0690ef
+ * The pathname may not be null terminated. It may be terminated by the end of
0690ef
+ * a buffer or inode literal area, and the start of the next region contains
0690ef
+ * unknown data. Therefore, when we get to the last component of the symlink, we
0690ef
+ * cannot assume that strlen() will give us the right result. Hence we need to
0690ef
+ * track the remaining pathname length and use that instead.
0690ef
+ */
0690ef
 static void
0690ef
 obfuscate_path_components(
0690ef
 	char			*buf,
0690ef
 	__uint64_t		len)
0690ef
 {
0690ef
-	uchar_t			*comp;
0690ef
+	uchar_t			*comp = (uchar_t *)buf;
0690ef
+	uchar_t			*end = comp + len;
0690ef
 	xfs_dahash_t		hash;
0690ef
 
0690ef
-	comp = (uchar_t *)buf;
0690ef
-	while (comp < (uchar_t *)buf + len) {
0690ef
+	while (comp < end) {
0690ef
 		char	*slash;
0690ef
 		int	namelen;
0690ef
 
0690ef
@@ -991,7 +1039,7 @@ obfuscate_path_components(
0690ef
 		slash = strchr((char *)comp, '/');
0690ef
 		if (!slash) {
0690ef
 			/* last (or single) component */
0690ef
-			namelen = strlen((char *)comp);
0690ef
+			namelen = strnlen((char *)comp, len);
0690ef
 			hash = libxfs_da_hashname(comp, namelen);
0690ef
 			obfuscate_name(hash, namelen, comp);
0690ef
 			break;
0690ef
@@ -1000,11 +1048,13 @@ obfuscate_path_components(
0690ef
 		/* handle leading or consecutive slashes */
0690ef
 		if (!namelen) {
0690ef
 			comp++;
0690ef
+			len--;
0690ef
 			continue;
0690ef
 		}
0690ef
 		hash = libxfs_da_hashname(comp, namelen);
0690ef
 		obfuscate_name(hash, namelen, comp);
0690ef
 		comp += namelen + 1;
0690ef
+		len -= namelen + 1;
0690ef
 	}
0690ef
 }
0690ef
 
0690ef
@@ -1080,24 +1130,11 @@ obfuscate_sf_attr(
0690ef
 	}
0690ef
 }
0690ef
 
0690ef
-/*
0690ef
- * dir_data structure is used to track multi-fsblock dir2 blocks between extent
0690ef
- * processing calls.
0690ef
- */
0690ef
-
0690ef
-static struct dir_data_s {
0690ef
-	int			end_of_data;
0690ef
-	int			block_index;
0690ef
-	int			offset_to_entry;
0690ef
-	int			bad_block;
0690ef
-} dir_data;
0690ef
-
0690ef
 static void
0690ef
-obfuscate_dir_data_blocks(
0690ef
-	char			*block,
0690ef
-	xfs_dfiloff_t		offset,
0690ef
-	xfs_dfilblks_t		count,
0690ef
-	int			is_block_format)
0690ef
+obfuscate_dir_data_block(
0690ef
+	char		*block,
0690ef
+	xfs_dfiloff_t	offset,
0690ef
+	int		is_block_format)
0690ef
 {
0690ef
 	/*
0690ef
 	 * we have to rely on the fileoffset and signature of the block to
0690ef
@@ -1105,133 +1142,105 @@ obfuscate_dir_data_blocks(
0690ef
 	 * for multi-fsblock dir blocks, if a name crosses an extent boundary,
0690ef
 	 * ignore it and continue.
0690ef
 	 */
0690ef
-	int			c;
0690ef
-	int			dir_offset;
0690ef
-	char			*ptr;
0690ef
-	char			*endptr;
0690ef
-
0690ef
-	if (is_block_format && count != mp->m_dirblkfsbs)
0690ef
-		return; /* too complex to handle this rare case */
0690ef
-
0690ef
-	for (c = 0, endptr = block; c < count; c++) {
0690ef
-
0690ef
-		if (dir_data.block_index == 0) {
0690ef
-			int		wantmagic;
0690ef
-			struct xfs_dir2_data_hdr *datahdr;
0690ef
-
0690ef
-			datahdr = (struct xfs_dir2_data_hdr *)block;
0690ef
-
0690ef
-			if (offset % mp->m_dirblkfsbs != 0)
0690ef
-				return;	/* corrupted, leave it alone */
0690ef
-
0690ef
-			dir_data.bad_block = 0;
0690ef
-
0690ef
-			if (is_block_format) {
0690ef
-				xfs_dir2_leaf_entry_t	*blp;
0690ef
-				xfs_dir2_block_tail_t	*btp;
0690ef
-
0690ef
-				btp = xfs_dir2_block_tail_p(mp, datahdr);
0690ef
-				blp = xfs_dir2_block_leaf_p(btp);
0690ef
-				if ((char *)blp > (char *)btp)
0690ef
-					blp = (xfs_dir2_leaf_entry_t *)btp;
0690ef
-
0690ef
-				dir_data.end_of_data = (char *)blp - block;
0690ef
-				wantmagic = XFS_DIR2_BLOCK_MAGIC;
0690ef
-			} else { /* leaf/node format */
0690ef
-				dir_data.end_of_data = mp->m_dirblkfsbs <<
0690ef
-						mp->m_sb.sb_blocklog;
0690ef
-				wantmagic = XFS_DIR2_DATA_MAGIC;
0690ef
-			}
0690ef
-			dir_data.offset_to_entry =
0690ef
-					xfs_dir3_data_entry_offset(datahdr);
0690ef
+	int		dir_offset;
0690ef
+	char		*ptr;
0690ef
+	char		*endptr;
0690ef
+	int		end_of_data;
0690ef
+	int		wantmagic;
0690ef
+	struct xfs_dir2_data_hdr *datahdr;
0690ef
+
0690ef
+	datahdr = (struct xfs_dir2_data_hdr *)block;
0690ef
+
0690ef
+	if (offset % mp->m_dirblkfsbs != 0)
0690ef
+		return;	/* corrupted, leave it alone */
0690ef
+
0690ef
+	if (is_block_format) {
0690ef
+		xfs_dir2_leaf_entry_t	*blp;
0690ef
+		xfs_dir2_block_tail_t	*btp;
0690ef
+
0690ef
+		btp = xfs_dir2_block_tail_p(mp, datahdr);
0690ef
+		blp = xfs_dir2_block_leaf_p(btp);
0690ef
+		if ((char *)blp > (char *)btp)
0690ef
+			blp = (xfs_dir2_leaf_entry_t *)btp;
0690ef
+
0690ef
+		end_of_data = (char *)blp - block;
0690ef
+		if (xfs_sb_version_hascrc(&mp->m_sb))
0690ef
+			wantmagic = XFS_DIR3_BLOCK_MAGIC;
0690ef
+		else
0690ef
+			wantmagic = XFS_DIR2_BLOCK_MAGIC;
0690ef
+	} else { /* leaf/node format */
0690ef
+		end_of_data = mp->m_dirblkfsbs << mp->m_sb.sb_blocklog;
0690ef
+		if (xfs_sb_version_hascrc(&mp->m_sb))
0690ef
+			wantmagic = XFS_DIR3_DATA_MAGIC;
0690ef
+		else
0690ef
+			wantmagic = XFS_DIR2_DATA_MAGIC;
0690ef
+	}
0690ef
 
0690ef
-			if (be32_to_cpu(datahdr->magic) != wantmagic) {
0690ef
-				if (show_warnings)
0690ef
-					print_warning("invalid magic in dir "
0690ef
-						"inode %llu block %ld",
0690ef
-						(long long)cur_ino,
0690ef
-						(long)offset);
0690ef
-				dir_data.bad_block = 1;
0690ef
-			}
0690ef
-		}
0690ef
-		dir_data.block_index++;
0690ef
-		if (dir_data.block_index == mp->m_dirblkfsbs)
0690ef
-			dir_data.block_index = 0;
0690ef
+	if (be32_to_cpu(datahdr->magic) != wantmagic) {
0690ef
+		if (show_warnings)
0690ef
+			print_warning(
0690ef
+		"invalid magic in dir inode %llu block %ld",
0690ef
+					(long long)cur_ino, (long)offset);
0690ef
+		return;
0690ef
+	}
0690ef
 
0690ef
-		if (dir_data.bad_block)
0690ef
-			continue;
0690ef
+	dir_offset = xfs_dir3_data_entry_offset(datahdr);
0690ef
+	ptr = block + dir_offset;
0690ef
+	endptr = block + mp->m_sb.sb_blocksize;
0690ef
 
0690ef
-		dir_offset = (dir_data.block_index << mp->m_sb.sb_blocklog) +
0690ef
-				dir_data.offset_to_entry;
0690ef
-
0690ef
-		ptr = endptr + dir_data.offset_to_entry;
0690ef
-		endptr += mp->m_sb.sb_blocksize;
0690ef
-
0690ef
-		while (ptr < endptr && dir_offset < dir_data.end_of_data) {
0690ef
-			xfs_dir2_data_entry_t	*dep;
0690ef
-			xfs_dir2_data_unused_t	*dup;
0690ef
-			int			length;
0690ef
-
0690ef
-			dup = (xfs_dir2_data_unused_t *)ptr;
0690ef
-
0690ef
-			if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
0690ef
-				int	length = be16_to_cpu(dup->length);
0690ef
-				if (dir_offset + length > dir_data.end_of_data ||
0690ef
-						length == 0 || (length &
0690ef
-						 (XFS_DIR2_DATA_ALIGN - 1))) {
0690ef
-					if (show_warnings)
0690ef
-						print_warning("invalid length "
0690ef
-							"for dir free space in "
0690ef
-							"inode %llu",
0690ef
-							(long long)cur_ino);
0690ef
-					dir_data.bad_block = 1;
0690ef
-					break;
0690ef
-				}
0690ef
-				if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
0690ef
-						dir_offset) {
0690ef
-					dir_data.bad_block = 1;
0690ef
-					break;
0690ef
-				}
0690ef
-				dir_offset += length;
0690ef
-				ptr += length;
0690ef
-				if (dir_offset >= dir_data.end_of_data ||
0690ef
-						ptr >= endptr)
0690ef
-					break;
0690ef
-			}
0690ef
+	while (ptr < endptr && dir_offset < end_of_data) {
0690ef
+		xfs_dir2_data_entry_t	*dep;
0690ef
+		xfs_dir2_data_unused_t	*dup;
0690ef
+		int			length;
0690ef
 
0690ef
-			dep = (xfs_dir2_data_entry_t *)ptr;
0690ef
-			length = xfs_dir3_data_entsize(mp, dep->namelen);
0690ef
+		dup = (xfs_dir2_data_unused_t *)ptr;
0690ef
 
0690ef
-			if (dir_offset + length > dir_data.end_of_data ||
0690ef
-					ptr + length > endptr) {
0690ef
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
0690ef
+			int	length = be16_to_cpu(dup->length);
0690ef
+			if (dir_offset + length > end_of_data ||
0690ef
+			    !length || (length & (XFS_DIR2_DATA_ALIGN - 1))) {
0690ef
 				if (show_warnings)
0690ef
-					print_warning("invalid length for "
0690ef
-						"dir entry name in inode %llu",
0690ef
+					print_warning(
0690ef
+			"invalid length for dir free space in inode %llu",
0690ef
 						(long long)cur_ino);
0690ef
-				break;
0690ef
+				return;
0690ef
 			}
0690ef
-			if (be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) !=
0690ef
-					dir_offset) {
0690ef
-				dir_data.bad_block = 1;
0690ef
-				break;
0690ef
-			}
0690ef
-			generate_obfuscated_name(be64_to_cpu(dep->inumber),
0690ef
-					dep->namelen, &dep->name[0]);
0690ef
+			if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
0690ef
+					dir_offset)
0690ef
+				return;
0690ef
 			dir_offset += length;
0690ef
 			ptr += length;
0690ef
+			if (dir_offset >= end_of_data || ptr >= endptr)
0690ef
+				return;
0690ef
+		}
0690ef
+
0690ef
+		dep = (xfs_dir2_data_entry_t *)ptr;
0690ef
+		length = xfs_dir3_data_entsize(mp, dep->namelen);
0690ef
+
0690ef
+		if (dir_offset + length > end_of_data ||
0690ef
+		    ptr + length > endptr) {
0690ef
+			if (show_warnings)
0690ef
+				print_warning(
0690ef
+			"invalid length for dir entry name in inode %llu",
0690ef
+					(long long)cur_ino);
0690ef
+			return;
0690ef
 		}
0690ef
-		dir_data.offset_to_entry = dir_offset &
0690ef
-						(mp->m_sb.sb_blocksize - 1);
0690ef
+		if (be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) !=
0690ef
+				dir_offset)
0690ef
+			return;
0690ef
+		generate_obfuscated_name(be64_to_cpu(dep->inumber),
0690ef
+					 dep->namelen, &dep->name[0]);
0690ef
+		dir_offset += length;
0690ef
+		ptr += length;
0690ef
 	}
0690ef
 }
0690ef
 
0690ef
 static void
0690ef
-obfuscate_symlink_blocks(
0690ef
-	char			*block,
0690ef
-	xfs_dfilblks_t		count)
0690ef
+obfuscate_symlink_block(
0690ef
+	char			*block)
0690ef
 {
0690ef
-	count <<= mp->m_sb.sb_blocklog;
0690ef
-	obfuscate_path_components(block, count);
0690ef
+	/* XXX: need to handle CRC headers */
0690ef
+	obfuscate_path_components(block, mp->m_sb.sb_blocksize);
0690ef
 }
0690ef
 
0690ef
 #define MAX_REMOTE_VALS		4095
0690ef
@@ -1252,86 +1261,227 @@ add_remote_vals(
0690ef
 		blockidx++;
0690ef
 		length -= XFS_LBSIZE(mp);
0690ef
 	}
0690ef
+
0690ef
+	if (attr_data.remote_val_count >= MAX_REMOTE_VALS) {
0690ef
+		print_warning(
0690ef
+"Overflowed attr obfuscation array. No longer obfuscating remote attrs.");
0690ef
+	}
0690ef
 }
0690ef
 
0690ef
 static void
0690ef
-obfuscate_attr_blocks(
0690ef
+obfuscate_attr_block(
0690ef
 	char			*block,
0690ef
-	xfs_dfiloff_t		offset,
0690ef
-	xfs_dfilblks_t		count)
0690ef
+	xfs_dfiloff_t		offset)
0690ef
 {
0690ef
 	xfs_attr_leafblock_t	*leaf;
0690ef
-	int			c;
0690ef
 	int			i;
0690ef
 	int			nentries;
0690ef
 	xfs_attr_leaf_entry_t 	*entry;
0690ef
 	xfs_attr_leaf_name_local_t *local;
0690ef
 	xfs_attr_leaf_name_remote_t *remote;
0690ef
 
0690ef
-	for (c = 0; c < count; c++, offset++, block += XFS_LBSIZE(mp)) {
0690ef
+	leaf = (xfs_attr_leafblock_t *)block;
0690ef
 
0690ef
-		leaf = (xfs_attr_leafblock_t *)block;
0690ef
-
0690ef
-		if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) {
0690ef
-			for (i = 0; i < attr_data.remote_val_count; i++) {
0690ef
-				if (attr_data.remote_vals[i] == offset)
0690ef
-					memset(block, 0, XFS_LBSIZE(mp));
0690ef
-			}
0690ef
-			continue;
0690ef
+	if (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) {
0690ef
+		for (i = 0; i < attr_data.remote_val_count; i++) {
0690ef
+			/* XXX: need to handle CRC headers */
0690ef
+			if (attr_data.remote_vals[i] == offset)
0690ef
+				memset(block, 0, XFS_LBSIZE(mp));
0690ef
 		}
0690ef
+		return;
0690ef
+	}
0690ef
 
0690ef
-		nentries = be16_to_cpu(leaf->hdr.count);
0690ef
-		if (nentries * sizeof(xfs_attr_leaf_entry_t) +
0690ef
-				sizeof(xfs_attr_leaf_hdr_t) > XFS_LBSIZE(mp)) {
0690ef
+	nentries = be16_to_cpu(leaf->hdr.count);
0690ef
+	if (nentries * sizeof(xfs_attr_leaf_entry_t) +
0690ef
+			sizeof(xfs_attr_leaf_hdr_t) > XFS_LBSIZE(mp)) {
0690ef
+		if (show_warnings)
0690ef
+			print_warning("invalid attr count in inode %llu",
0690ef
+					(long long)cur_ino);
0690ef
+		return;
0690ef
+	}
0690ef
+
0690ef
+	for (i = 0, entry = &leaf->entries[0]; i < nentries; i++, entry++) {
0690ef
+		if (be16_to_cpu(entry->nameidx) > XFS_LBSIZE(mp)) {
0690ef
 			if (show_warnings)
0690ef
-				print_warning("invalid attr count in inode %llu",
0690ef
+				print_warning(
0690ef
+				"invalid attr nameidx in inode %llu",
0690ef
 						(long long)cur_ino);
0690ef
-			continue;
0690ef
+			break;
0690ef
 		}
0690ef
-
0690ef
-		for (i = 0, entry = &leaf->entries[0]; i < nentries;
0690ef
-				i++, entry++) {
0690ef
-			if (be16_to_cpu(entry->nameidx) > XFS_LBSIZE(mp)) {
0690ef
+		if (entry->flags & XFS_ATTR_LOCAL) {
0690ef
+			local = xfs_attr3_leaf_name_local(leaf, i);
0690ef
+			if (local->namelen == 0) {
0690ef
 				if (show_warnings)
0690ef
-					print_warning("invalid attr nameidx "
0690ef
-							"in inode %llu",
0690ef
-							(long long)cur_ino);
0690ef
+					print_warning(
0690ef
+				"zero length for attr name in inode %llu",
0690ef
+						(long long)cur_ino);
0690ef
 				break;
0690ef
 			}
0690ef
-			if (entry->flags & XFS_ATTR_LOCAL) {
0690ef
-				local = xfs_attr3_leaf_name_local(leaf, i);
0690ef
-				if (local->namelen == 0) {
0690ef
-					if (show_warnings)
0690ef
-						print_warning("zero length for "
0690ef
-							"attr name in inode %llu",
0690ef
-							(long long)cur_ino);
0690ef
-					break;
0690ef
-				}
0690ef
-				generate_obfuscated_name(0, local->namelen,
0690ef
-					&local->nameval[0]);
0690ef
-				memset(&local->nameval[local->namelen], 0,
0690ef
-					be16_to_cpu(local->valuelen));
0690ef
-			} else {
0690ef
-				remote = xfs_attr3_leaf_name_remote(leaf, i);
0690ef
-				if (remote->namelen == 0 ||
0690ef
-						remote->valueblk == 0) {
0690ef
-					if (show_warnings)
0690ef
-						print_warning("invalid attr "
0690ef
-							"entry in inode %llu",
0690ef
-							(long long)cur_ino);
0690ef
-					break;
0690ef
-				}
0690ef
-				generate_obfuscated_name(0, remote->namelen,
0690ef
-					&remote->name[0]);
0690ef
-				add_remote_vals(be32_to_cpu(remote->valueblk),
0690ef
+			generate_obfuscated_name(0, local->namelen,
0690ef
+				&local->nameval[0]);
0690ef
+			memset(&local->nameval[local->namelen], 0,
0690ef
+				be16_to_cpu(local->valuelen));
0690ef
+		} else {
0690ef
+			remote = xfs_attr3_leaf_name_remote(leaf, i);
0690ef
+			if (remote->namelen == 0 || remote->valueblk == 0) {
0690ef
+				if (show_warnings)
0690ef
+					print_warning(
0690ef
+				"invalid attr entry in inode %llu",
0690ef
+						(long long)cur_ino);
0690ef
+				break;
0690ef
+			}
0690ef
+			generate_obfuscated_name(0, remote->namelen,
0690ef
+						 &remote->name[0]);
0690ef
+			add_remote_vals(be32_to_cpu(remote->valueblk),
0690ef
 					be32_to_cpu(remote->valuelen));
0690ef
+		}
0690ef
+	}
0690ef
+}
0690ef
+
0690ef
+static int
0690ef
+process_single_fsb_objects(
0690ef
+	xfs_dfiloff_t	o,
0690ef
+	xfs_dfsbno_t	s,
0690ef
+	xfs_dfilblks_t	c,
0690ef
+	typnm_t		btype,
0690ef
+	xfs_dfiloff_t	last)
0690ef
+{
0690ef
+	char		*dp;
0690ef
+	int		ret = 0;
0690ef
+	int		i;
0690ef
+
0690ef
+	for (i = 0; i < c; i++) {
0690ef
+		push_cur();
0690ef
+		set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), blkbb,
0690ef
+				DB_RING_IGN, NULL);
0690ef
+
0690ef
+		if (!iocur_top->data) {
0690ef
+			xfs_agnumber_t	agno = XFS_FSB_TO_AGNO(mp, s);
0690ef
+			xfs_agblock_t	agbno = XFS_FSB_TO_AGBNO(mp, s);
0690ef
+
0690ef
+			print_warning("cannot read %s block %u/%u (%llu)",
0690ef
+					typtab[btype].name, agno, agbno, s);
0690ef
+			if (stop_on_read_error)
0690ef
+				ret = -EIO;
0690ef
+			goto out_pop;
0690ef
+
0690ef
+		}
0690ef
+
0690ef
+		if (dont_obfuscate)
0690ef
+			goto write;
0690ef
+
0690ef
+		dp = iocur_top->data;
0690ef
+		switch (btype) {
0690ef
+		case TYP_DIR2:
0690ef
+			if (o >= mp->m_dirleafblk)
0690ef
+				break;
0690ef
+
0690ef
+			obfuscate_dir_data_block(dp, o,
0690ef
+						 last == mp->m_dirblkfsbs);
0690ef
+			iocur_top->need_crc = 1;
0690ef
+			break;
0690ef
+		case TYP_SYMLINK:
0690ef
+			obfuscate_symlink_block(dp);
0690ef
+			iocur_top->need_crc = 1;
0690ef
+			break;
0690ef
+		case TYP_ATTR:
0690ef
+			obfuscate_attr_block(dp, o);
0690ef
+			iocur_top->need_crc = 1;
0690ef
+			break;
0690ef
+		default:
0690ef
+			break;
0690ef
+		}
0690ef
+
0690ef
+write:
0690ef
+		ret = write_buf(iocur_top);
0690ef
+out_pop:
0690ef
+		pop_cur();
0690ef
+		if (ret)
0690ef
+			break;
0690ef
+		o++;
0690ef
+		s++;
0690ef
+	}
0690ef
+
0690ef
+	return ret;
0690ef
+}
0690ef
+
0690ef
+/*
0690ef
+ * Static map to aggregate multiple extents into a single directory block.
0690ef
+ */
0690ef
+static struct bbmap mfsb_map;
0690ef
+static int mfsb_length;
0690ef
+
0690ef
+static int
0690ef
+process_multi_fsb_objects(
0690ef
+	xfs_dfiloff_t	o,
0690ef
+	xfs_dfsbno_t	s,
0690ef
+	xfs_dfilblks_t	c,
0690ef
+	typnm_t		btype,
0690ef
+	xfs_dfiloff_t	last)
0690ef
+{
0690ef
+	int		ret = 0;
0690ef
+
0690ef
+	switch (btype) {
0690ef
+	case TYP_DIR2:
0690ef
+		break;
0690ef
+	default:
0690ef
+		print_warning("bad type for multi-fsb object %d", btype);
0690ef
+		return -EINVAL;
0690ef
+	}
0690ef
+
0690ef
+	while (c > 0) {
0690ef
+		unsigned int	bm_len;
0690ef
+
0690ef
+		if (mfsb_length + c >= mp->m_dirblkfsbs) {
0690ef
+			bm_len = mp->m_dirblkfsbs - mfsb_length;
0690ef
+			mfsb_length = 0;
0690ef
+		} else {
0690ef
+			mfsb_length += c;
0690ef
+			bm_len = c;
0690ef
+		}
0690ef
+
0690ef
+		mfsb_map.b[mfsb_map.nmaps].bm_bn = XFS_FSB_TO_DADDR(mp, s);
0690ef
+		mfsb_map.b[mfsb_map.nmaps].bm_len = XFS_FSB_TO_BB(mp, bm_len);
0690ef
+		mfsb_map.nmaps++;
0690ef
+
0690ef
+		if (mfsb_length == 0) {
0690ef
+			push_cur();
0690ef
+			set_cur(&typtab[btype], 0, 0, DB_RING_IGN, &mfsb_map);
0690ef
+			if (!iocur_top->data) {
0690ef
+				xfs_agnumber_t	agno = XFS_FSB_TO_AGNO(mp, s);
0690ef
+				xfs_agblock_t	agbno = XFS_FSB_TO_AGBNO(mp, s);
0690ef
+
0690ef
+				print_warning("cannot read %s block %u/%u (%llu)",
0690ef
+						typtab[btype].name, agno, agbno, s);
0690ef
+				if (stop_on_read_error)
0690ef
+					ret = -1;
0690ef
+				goto out_pop;
0690ef
+
0690ef
+			}
0690ef
+
0690ef
+			if (dont_obfuscate || o >= mp->m_dirleafblk) {
0690ef
+				ret = write_buf(iocur_top);
0690ef
+				goto out_pop;
0690ef
 			}
0690ef
+
0690ef
+			obfuscate_dir_data_block(iocur_top->data, o,
0690ef
+						  last == mp->m_dirblkfsbs);
0690ef
+			iocur_top->need_crc = 1;
0690ef
+			ret = write_buf(iocur_top);
0690ef
+out_pop:
0690ef
+			pop_cur();
0690ef
+			mfsb_map.nmaps = 0;
0690ef
+			if (ret)
0690ef
+				break;
0690ef
 		}
0690ef
+		c -= bm_len;
0690ef
+		s += bm_len;
0690ef
 	}
0690ef
+
0690ef
+	return ret;
0690ef
 }
0690ef
 
0690ef
 /* inode copy routines */
0690ef
-
0690ef
 static int
0690ef
 process_bmbt_reclist(
0690ef
 	xfs_bmbt_rec_t 		*rp,
0690ef
@@ -1346,6 +1496,7 @@ process_bmbt_reclist(
0690ef
 	xfs_dfiloff_t		last;
0690ef
 	xfs_agnumber_t		agno;
0690ef
 	xfs_agblock_t		agbno;
0690ef
+	int			error;
0690ef
 
0690ef
 	if (btype == TYP_DATA)
0690ef
 		return 1;
0690ef
@@ -1407,44 +1558,14 @@ process_bmbt_reclist(
0690ef
 			break;
0690ef
 		}
0690ef
 
0690ef
-		push_cur();
0690ef
-		set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), c * blkbb,
0690ef
-				DB_RING_IGN, NULL);
0690ef
-		if (iocur_top->data == NULL) {
0690ef
-			print_warning("cannot read %s block %u/%u (%llu)",
0690ef
-					typtab[btype].name, agno, agbno, s);
0690ef
-			if (stop_on_read_error) {
0690ef
-				pop_cur();
0690ef
-				return 0;
0690ef
-			}
0690ef
+		/* multi-extent blocks require special handling */
0690ef
+		if (btype != TYP_DIR2 || mp->m_dirblkfsbs == 1) {
0690ef
+			error = process_single_fsb_objects(o, s, c, btype, last);
0690ef
 		} else {
0690ef
-			if (!dont_obfuscate)
0690ef
-			    switch (btype) {
0690ef
-				case TYP_DIR2:
0690ef
-					if (o < mp->m_dirleafblk)
0690ef
-						obfuscate_dir_data_blocks(
0690ef
-							iocur_top->data, o, c,
0690ef
-							last == mp->m_dirblkfsbs);
0690ef
-					break;
0690ef
-
0690ef
-				case TYP_SYMLINK:
0690ef
-					obfuscate_symlink_blocks(
0690ef
-						iocur_top->data, c);
0690ef
-					break;
0690ef
-
0690ef
-				case TYP_ATTR:
0690ef
-					obfuscate_attr_blocks(iocur_top->data,
0690ef
-						o, c);
0690ef
-					break;
0690ef
-
0690ef
-				default: ;
0690ef
-			    }
0690ef
-			if (!write_buf(iocur_top)) {
0690ef
-				pop_cur();
0690ef
-				return 0;
0690ef
-			}
0690ef
+			error = process_multi_fsb_objects(o, s, c, btype, last);
0690ef
 		}
0690ef
-		pop_cur();
0690ef
+		if (error)
0690ef
+			return 0;
0690ef
 	}
0690ef
 
0690ef
 	return 1;
0690ef
@@ -1626,6 +1747,13 @@ process_inode_data(
0690ef
 	return 1;
0690ef
 }
0690ef
 
0690ef
+/*
0690ef
+ * when we process the inode, we may change the data in the data and/or
0690ef
+ * attribute fork if they are in short form and we are obfuscating names.
0690ef
+ * In this case we need to recalculate the CRC of the inode, but we should
0690ef
+ * only do that if the CRC in the inode is good to begin with. If the crc
0690ef
+ * is not ok, we just leave it alone.
0690ef
+ */
0690ef
 static int
0690ef
 process_inode(
0690ef
 	xfs_agnumber_t		agno,
0690ef
@@ -1633,18 +1761,30 @@ process_inode(
0690ef
 	xfs_dinode_t 		*dip)
0690ef
 {
0690ef
 	int			success;
0690ef
+	bool			crc_was_ok = false; /* no recalc by default */
0690ef
+	bool			need_new_crc = false;
0690ef
 
0690ef
 	success = 1;
0690ef
 	cur_ino = XFS_AGINO_TO_INO(mp, agno, agino);
0690ef
 
0690ef
+	/* we only care about crc recalculation if we are obfuscating names. */
0690ef
+	if (!dont_obfuscate) {
0690ef
+		crc_was_ok = xfs_verify_cksum((char *)dip,
0690ef
+					mp->m_sb.sb_inodesize,
0690ef
+					offsetof(struct xfs_dinode, di_crc));
0690ef
+	}
0690ef
+
0690ef
 	/* copy appropriate data fork metadata */
0690ef
 	switch (be16_to_cpu(dip->di_mode) & S_IFMT) {
0690ef
 		case S_IFDIR:
0690ef
-			memset(&dir_data, 0, sizeof(dir_data));
0690ef
 			success = process_inode_data(dip, TYP_DIR2);
0690ef
+			if (dip->di_format == XFS_DINODE_FMT_LOCAL)
0690ef
+				need_new_crc = 1;
0690ef
 			break;
0690ef
 		case S_IFLNK:
0690ef
 			success = process_inode_data(dip, TYP_SYMLINK);
0690ef
+			if (dip->di_format == XFS_DINODE_FMT_LOCAL)
0690ef
+				need_new_crc = 1;
0690ef
 			break;
0690ef
 		case S_IFREG:
0690ef
 			success = process_inode_data(dip, TYP_DATA);
0690ef
@@ -1659,6 +1799,7 @@ process_inode(
0690ef
 		attr_data.remote_val_count = 0;
0690ef
 		switch (dip->di_aformat) {
0690ef
 			case XFS_DINODE_FMT_LOCAL:
0690ef
+				need_new_crc = 1;
0690ef
 				if (!dont_obfuscate)
0690ef
 					obfuscate_sf_attr(dip);
0690ef
 				break;
0690ef
@@ -1673,6 +1814,9 @@ process_inode(
0690ef
 		}
0690ef
 		nametable_clear();
0690ef
 	}
0690ef
+
0690ef
+	if (crc_was_ok && need_new_crc)
0690ef
+		xfs_dinode_calc_crc(mp, dip);
0690ef
 	return success;
0690ef
 }
0690ef
 
0690ef
@@ -1743,12 +1887,9 @@ copy_inode_chunk(
0690ef
 
0690ef
 		if (!process_inode(agno, agino + i, dip))
0690ef
 			goto pop_out;
0690ef
-
0690ef
-		/* calculate the new CRC for the inode */
0690ef
-		xfs_dinode_calc_crc(mp, dip);
0690ef
 	}
0690ef
 skip_processing:
0690ef
-	if (!write_buf(iocur_top))
0690ef
+	if (write_buf(iocur_top))
0690ef
 		goto pop_out;
0690ef
 
0690ef
 	inodes_copied += XFS_INODES_PER_CHUNK;
0690ef
@@ -1866,7 +2007,7 @@ scan_ag(
0690ef
 		if (stop_on_read_error)
0690ef
 			goto pop_out;
0690ef
 	} else {
0690ef
-		if (!write_buf(iocur_top))
0690ef
+		if (write_buf(iocur_top))
0690ef
 			goto pop_out;
0690ef
 	}
0690ef
 
0690ef
@@ -1881,7 +2022,7 @@ scan_ag(
0690ef
 		if (stop_on_read_error)
0690ef
 			goto pop_out;
0690ef
 	} else {
0690ef
-		if (!write_buf(iocur_top))
0690ef
+		if (write_buf(iocur_top))
0690ef
 			goto pop_out;
0690ef
 	}
0690ef
 
0690ef
@@ -1896,7 +2037,7 @@ scan_ag(
0690ef
 		if (stop_on_read_error)
0690ef
 			goto pop_out;
0690ef
 	} else {
0690ef
-		if (!write_buf(iocur_top))
0690ef
+		if (write_buf(iocur_top))
0690ef
 			goto pop_out;
0690ef
 	}
0690ef
 
0690ef
@@ -1910,7 +2051,7 @@ scan_ag(
0690ef
 		if (stop_on_read_error)
0690ef
 			goto pop_out;
0690ef
 	} else {
0690ef
-		if (!write_buf(iocur_top))
0690ef
+		if (write_buf(iocur_top))
0690ef
 			goto pop_out;
0690ef
 	}
0690ef
 
0690ef
@@ -2015,7 +2156,7 @@ copy_log(void)
0690ef
 		print_warning("cannot read log");
0690ef
 		return !stop_on_read_error;
0690ef
 	}
0690ef
-	return write_buf(iocur_top);
0690ef
+	return !write_buf(iocur_top);
0690ef
 }
0690ef
 
0690ef
 static int
0690ef
@@ -2121,7 +2262,7 @@ metadump_f(
0690ef
 
0690ef
 	/* write the remaining index */
0690ef
 	if (!exitcode)
0690ef
-		exitcode = !write_index();
0690ef
+		exitcode = write_index() < 0;
0690ef
 
0690ef
 	if (progress_since_warning)
0690ef
 		fputc('\n', (outf == stdout) ? stderr : stdout);
0690ef
diff --git a/db/write.c b/db/write.c
0690ef
index 091ddb3..7b34fc0 100644
0690ef
--- a/db/write.c
0690ef
+++ b/db/write.c
0690ef
@@ -439,55 +439,78 @@ convert_oct(
0690ef
 
0690ef
 #define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
0690ef
 
0690ef
+/*
0690ef
+ * convert_arg allows input in the following forms:
0690ef
+ *
0690ef
+ *	- A string ("ABTB") whose ASCII value is placed in an array in the order
0690ef
+ *	matching the input.
0690ef
+ *
0690ef
+ *	- An even number of hex numbers. If the length is greater than 64 bits,
0690ef
+ *	then the output is an array of bytes whose top nibble is the first hex
0690ef
+ *	digit in the input, the lower nibble is the second hex digit in the
0690ef
+ *	input. UUID entries are entered in this manner.
0690ef
+ *
0690ef
+ *	- A decimal or hexadecimal integer to be used with setbitval().
0690ef
+ *
0690ef
+ * Numbers that are passed to setbitval() need to be in big endian format and
0690ef
+ * are adjusted in the buffer so that the first input bit is to be be written to
0690ef
+ * the first bit in the output.
0690ef
+ */
0690ef
 static char *
0690ef
 convert_arg(
0690ef
-	char *arg,
0690ef
-	int  bit_length)
0690ef
+	char		*arg,
0690ef
+	int		bit_length)
0690ef
 {
0690ef
-	int i;
0690ef
-	static char *buf = NULL;
0690ef
-	char *rbuf;
0690ef
-	long long *value;
0690ef
-	int alloc_size;
0690ef
-	char *ostr;
0690ef
-	int octval, ret;
0690ef
+	int		i;
0690ef
+	int		alloc_size;
0690ef
+	int		octval;
0690ef
+	int		offset;
0690ef
+	int		ret;
0690ef
+	static char	*buf = NULL;
0690ef
+	char		*endp;
0690ef
+	char		*rbuf;
0690ef
+	char		*ostr;
0690ef
+	__u64		*value;
0690ef
+	__u64		val = 0;
0690ef
 
0690ef
 	if (bit_length <= 64)
0690ef
 		alloc_size = 8;
0690ef
 	else
0690ef
-		alloc_size = (bit_length+7)/8;
0690ef
+		alloc_size = (bit_length + 7) / 8;
0690ef
 
0690ef
 	buf = xrealloc(buf, alloc_size);
0690ef
 	memset(buf, 0, alloc_size);
0690ef
-	value = (long long *)buf;
0690ef
+	value = (__u64 *)buf;
0690ef
 	rbuf = buf;
0690ef
 
0690ef
 	if (*arg == '\"') {
0690ef
-		/* handle strings */
0690ef
+		/* input a string and output ASCII array of characters */
0690ef
 
0690ef
 		/* zap closing quote if there is one */
0690ef
-		if ((ostr = strrchr(arg+1, '\"')) != NULL)
0690ef
+		ostr = strrchr(arg + 1, '\"');
0690ef
+		if (ostr)
0690ef
 			*ostr = '\0';
0690ef
 
0690ef
-		ostr = arg+1;
0690ef
+		ostr = arg + 1;
0690ef
 		for (i = 0; i < alloc_size; i++) {
0690ef
 			if (!*ostr)
0690ef
 				break;
0690ef
 
0690ef
-			/* do octal */
0690ef
+			/* do octal conversion */
0690ef
 			if (*ostr == '\\') {
0690ef
-				if (*(ostr+1) >= '0' || *(ostr+1) <= '7') {
0690ef
-					ret = convert_oct(ostr+1, &octval);
0690ef
+				if (*(ostr + 1) >= '0' || *(ostr + 1) <= '7') {
0690ef
+					ret = convert_oct(ostr + 1, &octval);
0690ef
 					*rbuf++ = octval;
0690ef
-					ostr += ret+1;
0690ef
+					ostr += ret + 1;
0690ef
 					continue;
0690ef
 				}
0690ef
 			}
0690ef
 			*rbuf++ = *ostr++;
0690ef
 		}
0690ef
-
0690ef
 		return buf;
0690ef
-	} else if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
0690ef
+	}
0690ef
+
0690ef
+	if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
0690ef
 		/*
0690ef
 		 * handle hex blocks ie
0690ef
 		 *    #00112233445566778899aabbccddeeff
0690ef
@@ -496,48 +519,79 @@ convert_arg(
0690ef
 		 *
0690ef
 		 * (but if it starts with "-" assume it's just an integer)
0690ef
 		 */
0690ef
-		int bytes=bit_length/8;
0690ef
+		int bytes = bit_length / NBBY;
0690ef
+
0690ef
+		/* is this an array of hec numbers? */
0690ef
+		if (bit_length % NBBY)
0690ef
+			return NULL;
0690ef
 
0690ef
 		/* skip leading hash */
0690ef
-		if (*arg=='#') arg++;
0690ef
+		if (*arg == '#')
0690ef
+			arg++;
0690ef
 
0690ef
 		while (*arg && bytes--) {
0690ef
-		    /* skip hypens */
0690ef
-		    while (*arg=='-') arg++;
0690ef
-
0690ef
-		    /* get first nybble */
0690ef
-		    if (!isxdigit((int)*arg)) return NULL;
0690ef
-		    *rbuf=NYBBLE((int)*arg)<<4;
0690ef
-		    arg++;
0690ef
-
0690ef
-		    /* skip more hyphens */
0690ef
-		    while (*arg=='-') arg++;
0690ef
-
0690ef
-		    /* get second nybble */
0690ef
-		    if (!isxdigit((int)*arg)) return NULL;
0690ef
-		    *rbuf++|=NYBBLE((int)*arg);
0690ef
-		    arg++;
0690ef
+			/* skip hypens */
0690ef
+			while (*arg == '-')
0690ef
+				arg++;
0690ef
+
0690ef
+			/* get first nybble */
0690ef
+			if (!isxdigit((int)*arg))
0690ef
+				return NULL;
0690ef
+			*rbuf = NYBBLE((int)*arg) << 4;
0690ef
+			arg++;
0690ef
+
0690ef
+			/* skip more hyphens */
0690ef
+			while (*arg == '-')
0690ef
+				arg++;
0690ef
+
0690ef
+			/* get second nybble */
0690ef
+			if (!isxdigit((int)*arg))
0690ef
+				return NULL;
0690ef
+			*rbuf++ |= NYBBLE((int)*arg);
0690ef
+			arg++;
0690ef
 		}
0690ef
-		if (bytes<0&&*arg) return NULL;
0690ef
+		if (bytes < 0 && *arg)
0690ef
+			return NULL;
0690ef
+
0690ef
 		return buf;
0690ef
-	} else {
0690ef
-		/*
0690ef
-		 * handle integers
0690ef
-		 */
0690ef
-		*value = strtoll(arg, NULL, 0);
0690ef
-
0690ef
-#if __BYTE_ORDER == BIG_ENDIAN
0690ef
-		/* hackery for big endian */
0690ef
-		if (bit_length <= 8) {
0690ef
-			rbuf += 7;
0690ef
-		} else if (bit_length <= 16) {
0690ef
-			rbuf += 6;
0690ef
-		} else if (bit_length <= 32) {
0690ef
-			rbuf += 4;
0690ef
-		}
0690ef
-#endif
0690ef
-		return rbuf;
0690ef
 	}
0690ef
+
0690ef
+	/* handle decimal / hexadecimal integers */
0690ef
+	val = strtoll(arg, &endp, 0);
0690ef
+	/* return if not a clean number */
0690ef
+	if (*endp != '\0')
0690ef
+		return NULL;
0690ef
+
0690ef
+	/* Does the value fit into the range of the destination bitfield? */
0690ef
+	if ((val >> bit_length) > 0)
0690ef
+		return NULL;
0690ef
+	/*
0690ef
+	 * If the length of the field is not a multiple of a byte, push
0690ef
+	 * the bits up in the field, so the most signicant field bit is
0690ef
+	 * the most significant bit in the byte:
0690ef
+	 *
0690ef
+	 * before:
0690ef
+	 * val  |----|----|----|----|----|--MM|mmmm|llll|
0690ef
+	 * after
0690ef
+	 * val  |----|----|----|----|----|MMmm|mmll|ll00|
0690ef
+	 */
0690ef
+	offset = bit_length % NBBY;
0690ef
+	if (offset)
0690ef
+		val <<= (NBBY - offset);
0690ef
+
0690ef
+	/*
0690ef
+	 * convert to big endian and copy into the array
0690ef
+	 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
0690ef
+	 */
0690ef
+	*value = cpu_to_be64(val);
0690ef
+
0690ef
+	/*
0690ef
+	 * Align the array to point to the field in the array.
0690ef
+	 *  rbuf  = |MMmm|mmll|ll00|
0690ef
+	 */
0690ef
+	offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64));
0690ef
+	rbuf += offset;
0690ef
+	return rbuf;
0690ef
 }
0690ef
 
0690ef
 
0690ef
@@ -550,9 +604,9 @@ write_struct(
0690ef
 {
0690ef
 	const ftattr_t	*fa;
0690ef
 	flist_t		*fl;
0690ef
-	flist_t         *sfl;
0690ef
-	int             bit_length;
0690ef
-	char            *buf;
0690ef
+	flist_t		*sfl;
0690ef
+	int		bit_length;
0690ef
+	char		*buf;
0690ef
 	int		parentoffset;
0690ef
 
0690ef
 	if (argc != 2) {
0690ef
diff --git a/db/xfs_metadump.sh b/db/xfs_metadump.sh
0690ef
index 28b04b8..a95d5a5 100755
0690ef
--- a/db/xfs_metadump.sh
0690ef
+++ b/db/xfs_metadump.sh
0690ef
@@ -5,9 +5,9 @@
0690ef
 
0690ef
 OPTS=" "
0690ef
 DBOPTS=" "
0690ef
-USAGE="Usage: xfs_metadump [-efogwV] [-m max_extents] [-l logdev] source target"
0690ef
+USAGE="Usage: xfs_metadump [-efFogwV] [-m max_extents] [-l logdev] source target"
0690ef
 
0690ef
-while getopts "efgl:m:owV" c
0690ef
+while getopts "efgl:m:owFV" c
0690ef
 do
0690ef
 	case $c in
0690ef
 	e)	OPTS=$OPTS"-e ";;
0690ef
@@ -17,6 +17,7 @@ do
0690ef
 	w)	OPTS=$OPTS"-w ";;
0690ef
 	f)	DBOPTS=$DBOPTS" -f";;
0690ef
 	l)	DBOPTS=$DBOPTS" -l "$OPTARG" ";;
0690ef
+	F)	DBOPTS=$DBOPTS" -F";;
0690ef
 	V)	xfs_db -p xfs_metadump -V
0690ef
 		status=$?
0690ef
 		exit $status
0690ef
@@ -29,7 +30,7 @@ done
0690ef
 set -- extra $@
0690ef
 shift $OPTIND
0690ef
 case $# in
0690ef
-	2)	xfs_db$DBOPTS -F -i -p xfs_metadump -c "metadump$OPTS $2" $1
0690ef
+	2)	xfs_db$DBOPTS -i -p xfs_metadump -c "metadump$OPTS $2" $1
0690ef
 		status=$?
0690ef
 		;;
0690ef
 	*)	echo $USAGE 1>&2
0690ef
diff --git a/growfs/xfs_growfs.c b/growfs/xfs_growfs.c
0690ef
index 2df68fb..fb7eda8 100644
0690ef
--- a/growfs/xfs_growfs.c
0690ef
+++ b/growfs/xfs_growfs.c
0690ef
@@ -189,7 +189,7 @@ main(int argc, char **argv)
0690ef
 		usage();
0690ef
 	if (iflag && xflag)
0690ef
 		usage();
0690ef
-	if (dflag + lflag + rflag == 0)
0690ef
+	if (dflag + lflag + rflag + mflag == 0)
0690ef
 		aflag = 1;
0690ef
 
0690ef
 	fs_table_initialise(0, NULL, 0, NULL);
0690ef
@@ -305,12 +305,15 @@ main(int argc, char **argv)
0690ef
 	drsize -= (drsize % 2);
0690ef
 
0690ef
 	error = 0;
0690ef
-	if (dflag | aflag) {
0690ef
+
0690ef
+	if (dflag | mflag | aflag) {
0690ef
 		xfs_growfs_data_t	in;
0690ef
 
0690ef
 		if (!mflag)
0690ef
 			maxpct = geo.imaxpct;
0690ef
-		if (!dsize)
0690ef
+		if (!dflag && !aflag)	/* Only mflag, no data size change */
0690ef
+			dsize = geo.datablocks;
0690ef
+		else if (!dsize)
0690ef
 			dsize = ddsize / (geo.blocksize / BBSIZE);
0690ef
 		else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
0690ef
 			fprintf(stderr, _(
0690ef
diff --git a/include/cache.h b/include/cache.h
0690ef
index 76cb234..0a84c69 100644
0690ef
--- a/include/cache.h
0690ef
+++ b/include/cache.h
0690ef
@@ -66,7 +66,8 @@ typedef void (*cache_walk_t)(struct cache_node *);
0690ef
 typedef struct cache_node * (*cache_node_alloc_t)(cache_key_t);
0690ef
 typedef void (*cache_node_flush_t)(struct cache_node *);
0690ef
 typedef void (*cache_node_relse_t)(struct cache_node *);
0690ef
-typedef unsigned int (*cache_node_hash_t)(cache_key_t, unsigned int);
0690ef
+typedef unsigned int (*cache_node_hash_t)(cache_key_t, unsigned int,
0690ef
+					  unsigned int);
0690ef
 typedef int (*cache_node_compare_t)(struct cache_node *, cache_key_t);
0690ef
 typedef unsigned int (*cache_bulk_relse_t)(struct cache *, struct list_head *);
0690ef
 
0690ef
@@ -112,6 +113,7 @@ struct cache {
0690ef
 	cache_node_compare_t	compare;	/* comparison routine */
0690ef
 	cache_bulk_relse_t	bulkrelse;	/* bulk release routine */
0690ef
 	unsigned int		c_hashsize;	/* hash bucket count */
0690ef
+	unsigned int		c_hashshift;	/* hash key shift */
0690ef
 	struct cache_hash	*c_hash;	/* hash table buckets */
0690ef
 	struct cache_mru	c_mrus[CACHE_MAX_PRIORITY + 1];
0690ef
 	unsigned long long	c_misses;	/* cache misses */
0690ef
diff --git a/include/darwin.h b/include/darwin.h
0690ef
index 97b8990..95f865b 100644
0690ef
--- a/include/darwin.h
0690ef
+++ b/include/darwin.h
0690ef
@@ -150,6 +150,7 @@ typedef unsigned char	uchar_t;
0690ef
 
0690ef
 #define ENOATTR		989     /* Attribute not found */
0690ef
 #define EFSCORRUPTED	990	/* Filesystem is corrupted */
0690ef
+#define EFSBADCRC	991	/* Bad CRC detected */
0690ef
 #define constpp		char * const *
0690ef
 
0690ef
 #define HAVE_FID	1
0690ef
diff --git a/include/freebsd.h b/include/freebsd.h
0690ef
index 2e1ae49..b51688b 100644
0690ef
--- a/include/freebsd.h
0690ef
+++ b/include/freebsd.h
0690ef
@@ -45,6 +45,7 @@
0690ef
 #define constpp	char * const *
0690ef
 
0690ef
 #define EFSCORRUPTED	990	/* Filesystem is corrupted */
0690ef
+#define EFSBADCRC	991	/* Bad CRC detected */
0690ef
 
0690ef
 typedef off_t		xfs_off_t;
0690ef
 typedef off_t		off64_t;
0690ef
diff --git a/include/gnukfreebsd.h b/include/gnukfreebsd.h
0690ef
index 1ec291f..2140acd 100644
0690ef
--- a/include/gnukfreebsd.h
0690ef
+++ b/include/gnukfreebsd.h
0690ef
@@ -36,6 +36,7 @@
0690ef
 #define constpp	char * const *
0690ef
 
0690ef
 #define EFSCORRUPTED	990	/* Filesystem is corrupted */
0690ef
+#define EFSBADCRC	991	/* Bad CRC detected */
0690ef
 
0690ef
 typedef off_t		xfs_off_t;
0690ef
 typedef __uint64_t	xfs_ino_t;
0690ef
diff --git a/include/irix.h b/include/irix.h
0690ef
index a450684..5040451 100644
0690ef
--- a/include/irix.h
0690ef
+++ b/include/irix.h
0690ef
@@ -52,6 +52,8 @@ typedef char*		xfs_caddr_t;
0690ef
 #define xfs_flock64	flock64
0690ef
 #define xfs_flock64_t	struct flock64
0690ef
 
0690ef
+#define EFSBADCRC	991	/* Bad CRC detected */
0690ef
+
0690ef
 typedef struct xfs_error_injection {
0690ef
 	__int32_t	fd;
0690ef
 	__int32_t	errtag;
0690ef
diff --git a/include/libxfs.h b/include/libxfs.h
0690ef
index 4bf331c..6bc6c94 100644
0690ef
--- a/include/libxfs.h
0690ef
+++ b/include/libxfs.h
0690ef
@@ -144,6 +144,7 @@ extern void	libxfs_device_close (dev_t);
0690ef
 extern int	libxfs_device_alignment (void);
0690ef
 extern void	libxfs_report(FILE *);
0690ef
 extern void	platform_findsizes(char *path, int fd, long long *sz, int *bsz);
0690ef
+extern int	platform_nproc(void);
0690ef
 
0690ef
 /* check or write log footer: specify device, log size in blocks & uuid */
0690ef
 typedef xfs_caddr_t (libxfs_get_block_t)(xfs_caddr_t, int, void *);
0690ef
@@ -364,7 +365,7 @@ enum xfs_buf_flags_t {	/* b_flags bits */
0690ef
 #define XFS_BUF_PRIORITY(bp)		(cache_node_get_priority( \
0690ef
 						(struct cache_node *)(bp)))
0690ef
 #define xfs_buf_set_ref(bp,ref)		((void) 0)
0690ef
-#define xfs_buf_ioerror(bp,err)		(bp)->b_error = (err);
0690ef
+#define xfs_buf_ioerror(bp,err)		((bp)->b_error = (err))
0690ef
 
0690ef
 #define xfs_daddr_to_agno(mp,d) \
0690ef
 	((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks))
0690ef
@@ -392,9 +393,9 @@ extern struct cache_operations	libxfs_bcache_operations;
0690ef
 #define libxfs_getbuf(dev, daddr, len) \
0690ef
 	libxfs_trace_getbuf(__FUNCTION__, __FILE__, __LINE__, \
0690ef
 			    (dev), (daddr), (len))
0690ef
-#define libxfs_getbuf_map(dev, map, nmaps) \
0690ef
+#define libxfs_getbuf_map(dev, map, nmaps, flags) \
0690ef
 	libxfs_trace_getbuf_map(__FUNCTION__, __FILE__, __LINE__, \
0690ef
-			    (dev), (map), (nmaps))
0690ef
+			    (dev), (map), (nmaps), (flags))
0690ef
 #define libxfs_getbuf_flags(dev, daddr, len, flags) \
0690ef
 	libxfs_trace_getbuf_flags(__FUNCTION__, __FILE__, __LINE__, \
0690ef
 			    (dev), (daddr), (len), (flags))
0690ef
@@ -412,7 +413,7 @@ extern int	libxfs_trace_writebuf(const char *, const char *, int,
0690ef
 extern xfs_buf_t *libxfs_trace_getbuf(const char *, const char *, int,
0690ef
 			struct xfs_buftarg *, xfs_daddr_t, int);
0690ef
 extern xfs_buf_t *libxfs_trace_getbuf_map(const char *, const char *, int,
0690ef
-			struct xfs_buftarg *, struct xfs_buf_map *, int);
0690ef
+			struct xfs_buftarg *, struct xfs_buf_map *, int, int);
0690ef
 extern xfs_buf_t *libxfs_trace_getbuf_flags(const char *, const char *, int,
0690ef
 			struct xfs_buftarg *, xfs_daddr_t, int, unsigned int);
0690ef
 extern void	libxfs_trace_putbuf (const char *, const char *, int,
0690ef
@@ -427,7 +428,7 @@ extern xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *,
0690ef
 extern int	libxfs_writebuf(xfs_buf_t *, int);
0690ef
 extern xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int);
0690ef
 extern xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *,
0690ef
-			struct xfs_buf_map *, int);
0690ef
+			struct xfs_buf_map *, int, int);
0690ef
 extern xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t,
0690ef
 			int, unsigned int);
0690ef
 extern void	libxfs_putbuf (xfs_buf_t *);
0690ef
@@ -448,8 +449,7 @@ extern void	libxfs_putbufr(xfs_buf_t *);
0690ef
 extern int	libxfs_writebuf_int(xfs_buf_t *, int);
0690ef
 extern int	libxfs_writebufr(struct xfs_buf *);
0690ef
 extern int	libxfs_readbufr(struct xfs_buftarg *, xfs_daddr_t, xfs_buf_t *, int, int);
0690ef
-extern int	libxfs_readbufr_map(struct xfs_buftarg *, struct xfs_buf *,
0690ef
-				    struct xfs_buf_map *, int, int);
0690ef
+extern int	libxfs_readbufr_map(struct xfs_buftarg *, struct xfs_buf *, int);
0690ef
 
0690ef
 extern int libxfs_bhash_size;
0690ef
 
0690ef
@@ -779,6 +779,20 @@ extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len);
0690ef
 
0690ef
 #include <xfs/xfs_cksum.h>
0690ef
 
0690ef
+static inline int
0690ef
+xfs_buf_verify_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
0690ef
+{
0690ef
+	return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
0690ef
+				cksum_offset);
0690ef
+}
0690ef
+
0690ef
+static inline void
0690ef
+xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
0690ef
+{
0690ef
+	xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
0690ef
+			 cksum_offset);
0690ef
+}
0690ef
+
0690ef
 #define xfs_notice(mp,fmt,args...)		cmn_err(CE_NOTE,fmt, ## args)
0690ef
 #define xfs_warn(mp,fmt,args...)		cmn_err(CE_WARN,fmt, ## args)
0690ef
 #define xfs_alert(mp,fmt,args...)		cmn_err(CE_ALERT,fmt, ## args)
0690ef
diff --git a/include/linux.h b/include/linux.h
0690ef
index 502fd1f..5586290 100644
0690ef
--- a/include/linux.h
0690ef
+++ b/include/linux.h
0690ef
@@ -136,6 +136,7 @@ platform_discard_blocks(int fd, uint64_t start, uint64_t len)
0690ef
 
0690ef
 #define ENOATTR		ENODATA	/* Attribute not found */
0690ef
 #define EFSCORRUPTED	EUCLEAN	/* Filesystem is corrupted */
0690ef
+#define EFSBADCRC	EBADMSG	/* Bad CRC detected */
0690ef
 
0690ef
 typedef loff_t		xfs_off_t;
0690ef
 typedef __uint64_t	xfs_ino_t;
0690ef
diff --git a/include/xfs_ag.h b/include/xfs_ag.h
0690ef
index 3fc1098..0fdd410 100644
0690ef
--- a/include/xfs_ag.h
0690ef
+++ b/include/xfs_ag.h
0690ef
@@ -89,6 +89,8 @@ typedef struct xfs_agf {
0690ef
 	/* structure must be padded to 64 bit alignment */
0690ef
 } xfs_agf_t;
0690ef
 
0690ef
+#define XFS_AGF_CRC_OFF		offsetof(struct xfs_agf, agf_crc)
0690ef
+
0690ef
 #define	XFS_AGF_MAGICNUM	0x00000001
0690ef
 #define	XFS_AGF_VERSIONNUM	0x00000002
0690ef
 #define	XFS_AGF_SEQNO		0x00000004
0690ef
@@ -167,6 +169,8 @@ typedef struct xfs_agi {
0690ef
 	/* structure must be padded to 64 bit alignment */
0690ef
 } xfs_agi_t;
0690ef
 
0690ef
+#define XFS_AGI_CRC_OFF		offsetof(struct xfs_agi, agi_crc)
0690ef
+
0690ef
 #define	XFS_AGI_MAGICNUM	0x00000001
0690ef
 #define	XFS_AGI_VERSIONNUM	0x00000002
0690ef
 #define	XFS_AGI_SEQNO		0x00000004
0690ef
@@ -222,6 +226,8 @@ typedef struct xfs_agfl {
0690ef
 	__be32		agfl_bno[];	/* actually XFS_AGFL_SIZE(mp) */
0690ef
 } xfs_agfl_t;
0690ef
 
0690ef
+#define XFS_AGFL_CRC_OFF	offsetof(struct xfs_agfl, agfl_crc)
0690ef
+
0690ef
 /*
0690ef
  * tags for inode radix tree
0690ef
  */
0690ef
diff --git a/include/xfs_dinode.h b/include/xfs_dinode.h
0690ef
index e5869b5..623bbe8 100644
0690ef
--- a/include/xfs_dinode.h
0690ef
+++ b/include/xfs_dinode.h
0690ef
@@ -89,6 +89,8 @@ typedef struct xfs_dinode {
0690ef
 	/* structure must be padded to 64 bit alignment */
0690ef
 } xfs_dinode_t;
0690ef
 
0690ef
+#define XFS_DINODE_CRC_OFF	offsetof(struct xfs_dinode, di_crc)
0690ef
+
0690ef
 #define DI_MAX_FLUSH 0xffff
0690ef
 
0690ef
 /*
0690ef
diff --git a/include/xfs_dir2.h b/include/xfs_dir2.h
0690ef
index 9910401..3900130 100644
0690ef
--- a/include/xfs_dir2.h
0690ef
+++ b/include/xfs_dir2.h
0690ef
@@ -57,6 +57,9 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
0690ef
 extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
0690ef
 				struct xfs_name *name, uint resblks);
0690ef
 
0690ef
+#define S_SHIFT 12
0690ef
+extern const unsigned char xfs_mode_to_ftype[];
0690ef
+
0690ef
 /*
0690ef
  * Direct call from the bmap code, bypassing the generic directory layer.
0690ef
  */
0690ef
diff --git a/include/xfs_format.h b/include/xfs_format.h
0690ef
index 997c770..77f6b8b 100644
0690ef
--- a/include/xfs_format.h
0690ef
+++ b/include/xfs_format.h
0690ef
@@ -145,6 +145,8 @@ struct xfs_dsymlink_hdr {
0690ef
 	__be64	sl_lsn;
0690ef
 };
0690ef
 
0690ef
+#define XFS_SYMLINK_CRC_OFF	offsetof(struct xfs_dsymlink_hdr, sl_crc)
0690ef
+
0690ef
 /*
0690ef
  * The maximum pathlen is 1024 bytes. Since the minimum file system
0690ef
  * blocksize is 512 bytes, we can get a max of 3 extents back from
0690ef
diff --git a/include/xfs_sb.h b/include/xfs_sb.h
0690ef
index 35061d4..f7b2fe7 100644
0690ef
--- a/include/xfs_sb.h
0690ef
+++ b/include/xfs_sb.h
0690ef
@@ -182,6 +182,8 @@ typedef struct xfs_sb {
0690ef
 	/* must be padded to 64 bit alignment */
0690ef
 } xfs_sb_t;
0690ef
 
0690ef
+#define XFS_SB_CRC_OFF		offsetof(struct xfs_sb, sb_crc)
0690ef
+
0690ef
 /*
0690ef
  * Superblock - on disk version.  Must match the in core version above.
0690ef
  * Must be padded to 64 bit alignment.
0690ef
diff --git a/io/file.c b/io/file.c
0690ef
index db85ffc..73b893f 100644
0690ef
--- a/io/file.c
0690ef
+++ b/io/file.c
0690ef
@@ -36,7 +36,7 @@ print_fileio(
0690ef
 	int		index,
0690ef
 	int		braces)
0690ef
 {
0690ef
-	printf(_("%c%03d%c %-14s (%s,%s,%s,%s%s%s%s)\n"),
0690ef
+	printf(_("%c%03d%c %-14s (%s,%s,%s,%s%s%s%s%s)\n"),
0690ef
 		braces? '[' : ' ', index, braces? ']' : ' ', file->name,
0690ef
 		file->flags & IO_FOREIGN ? _("foreign") : _("xfs"),
0690ef
 		file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
0690ef
@@ -44,7 +44,8 @@ print_fileio(
0690ef
 		file->flags & IO_READONLY ? _("read-only") : _("read-write"),
0690ef
 		file->flags & IO_REALTIME ? _(",real-time") : "",
0690ef
 		file->flags & IO_APPEND ? _(",append-only") : "",
0690ef
-		file->flags & IO_NONBLOCK ? _(",non-block") : "");
0690ef
+		file->flags & IO_NONBLOCK ? _(",non-block") : "",
0690ef
+		file->flags & IO_TMPFILE ? _(",tmpfile") : "");
0690ef
 }
0690ef
 
0690ef
 int
0690ef
diff --git a/io/imap.c b/io/imap.c
0690ef
index 0a4f14e..4f3f883 100644
0690ef
--- a/io/imap.c
0690ef
+++ b/io/imap.c
0690ef
@@ -67,7 +67,7 @@ imap_init(void)
0690ef
 	imap_cmd.name = "imap";
0690ef
 	imap_cmd.cfunc = imap_f;
0690ef
 	imap_cmd.argmin = 0;
0690ef
-	imap_cmd.argmax = 0;
0690ef
+	imap_cmd.argmax = 1;
0690ef
 	imap_cmd.args = _("[nentries]");
0690ef
 	imap_cmd.flags = CMD_NOMAP_OK;
0690ef
 	imap_cmd.oneline = _("inode map for filesystem of current file");
0690ef
diff --git a/io/init.c b/io/init.c
0690ef
index ef9e4cb..1e2690e 100644
0690ef
--- a/io/init.c
0690ef
+++ b/io/init.c
0690ef
@@ -136,7 +136,7 @@ init(
0690ef
 	pagesize = getpagesize();
0690ef
 	gettimeofday(&stopwatch, NULL);
0690ef
 
0690ef
-	while ((c = getopt(argc, argv, "ac:dFfmp:nrRstVx")) != EOF) {
0690ef
+	while ((c = getopt(argc, argv, "ac:dFfmp:nrRstTVx")) != EOF) {
0690ef
 		switch (c) {
0690ef
 		case 'a':
0690ef
 			flags |= IO_APPEND;
0690ef
@@ -179,6 +179,9 @@ init(
0690ef
 		case 'R':
0690ef
 			flags |= IO_REALTIME;
0690ef
 			break;
0690ef
+		case 'T':
0690ef
+			flags |= IO_TMPFILE;
0690ef
+			break;
0690ef
 		case 'x':
0690ef
 			expert = 1;
0690ef
 			break;
0690ef
diff --git a/io/io.h b/io/io.h
0690ef
index 6c3f627..0d2d768 100644
0690ef
--- a/io/io.h
0690ef
+++ b/io/io.h
0690ef
@@ -35,6 +35,7 @@
0690ef
 #define IO_TRUNC	(1<<6)
0690ef
 #define IO_FOREIGN	(1<<7)
0690ef
 #define IO_NONBLOCK	(1<<8)
0690ef
+#define IO_TMPFILE	(1<<9)
0690ef
 
0690ef
 /*
0690ef
  * Regular file I/O control
0690ef
diff --git a/io/open.c b/io/open.c
0690ef
index cc677e6..c106fa7 100644
0690ef
--- a/io/open.c
0690ef
+++ b/io/open.c
0690ef
@@ -22,6 +22,22 @@
0690ef
 #include "init.h"
0690ef
 #include "io.h"
0690ef
 
0690ef
+#ifndef __O_TMPFILE
0690ef
+#if defined __alpha__
0690ef
+#define __O_TMPFILE	0100000000
0690ef
+#elif defined(__hppa__)
0690ef
+#define __O_TMPFILE	 040000000
0690ef
+#elif defined(__sparc__)
0690ef
+#define __O_TMPFILE	 0x2000000
0690ef
+#else
0690ef
+#define __O_TMPFILE	 020000000
0690ef
+#endif
0690ef
+#endif /* __O_TMPFILE */
0690ef
+
0690ef
+#ifndef O_TMPFILE
0690ef
+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
0690ef
+#endif
0690ef
+
0690ef
 static cmdinfo_t open_cmd;
0690ef
 static cmdinfo_t stat_cmd;
0690ef
 static cmdinfo_t close_cmd;
0690ef
@@ -77,13 +93,14 @@ stat_f(
0690ef
 	int		verbose = (argc == 2 && !strcmp(argv[1], "-v"));
0690ef
 
0690ef
 	printf(_("fd.path = \"%s\"\n"), file->name);
0690ef
-	printf(_("fd.flags = %s,%s,%s%s%s%s\n"),
0690ef
+	printf(_("fd.flags = %s,%s,%s%s%s%s%s\n"),
0690ef
 		file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
0690ef
 		file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
0690ef
 		file->flags & IO_READONLY ? _("read-only") : _("read-write"),
0690ef
 		file->flags & IO_REALTIME ? _(",real-time") : "",
0690ef
 		file->flags & IO_APPEND ? _(",append-only") : "",
0690ef
-		file->flags & IO_NONBLOCK ? _(",non-block") : "");
0690ef
+		file->flags & IO_NONBLOCK ? _(",non-block") : "",
0690ef
+		file->flags & IO_TMPFILE ? _(",tmpfile") : "");
0690ef
 	if (fstat64(file->fd, &st) < 0) {
0690ef
 		perror("fstat64");
0690ef
 	} else {
0690ef
@@ -143,10 +160,13 @@ openfile(
0690ef
 		oflags |= O_TRUNC;
0690ef
 	if (flags & IO_NONBLOCK)
0690ef
 		oflags |= O_NONBLOCK;
0690ef
+	if (flags & IO_TMPFILE)
0690ef
+		oflags |= O_TMPFILE;
0690ef
 
0690ef
 	fd = open(path, oflags, mode);
0690ef
 	if (fd < 0) {
0690ef
-		if ((errno == EISDIR) && (oflags & O_RDWR)) {
0690ef
+		if (errno == EISDIR &&
0690ef
+		    ((oflags & (O_RDWR|O_TMPFILE)) == O_RDWR)) {
0690ef
 			/* make it as if we asked for O_RDONLY & try again */
0690ef
 			oflags &= ~O_RDWR;
0690ef
 			oflags |= O_RDONLY;
0690ef
@@ -248,6 +268,7 @@ open_help(void)
0690ef
 " -s -- open with O_SYNC\n"
0690ef
 " -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n"
0690ef
 " -R -- mark the file as a realtime XFS file immediately after opening it\n"
0690ef
+" -T -- open with O_TMPFILE (create a file not visible in the namespace)\n"
0690ef
 " Note1: usually read/write direct IO requests must be blocksize aligned;\n"
0690ef
 "        some kernels, however, allow sectorsize alignment for direct IO.\n"
0690ef
 " Note2: the bmap for non-regular files can be obtained provided the file\n"
0690ef
@@ -272,7 +293,7 @@ open_f(
0690ef
 		return 0;
0690ef
 	}
0690ef
 
0690ef
-	while ((c = getopt(argc, argv, "FRacdfm:nrstx")) != EOF) {
0690ef
+	while ((c = getopt(argc, argv, "FRTacdfm:nrstx")) != EOF) {
0690ef
 		switch (c) {
0690ef
 		case 'F':
0690ef
 			/* Ignored / deprecated now, handled automatically */
0690ef
@@ -310,6 +331,9 @@ open_f(
0690ef
 		case 'x':	/* backwards compatibility */
0690ef
 			flags |= IO_REALTIME;
0690ef
 			break;
0690ef
+		case 'T':
0690ef
+			flags |= IO_TMPFILE;
0690ef
+			break;
0690ef
 		default:
0690ef
 			return command_usage(&open_cmd);
0690ef
 		}
0690ef
@@ -318,6 +342,11 @@ open_f(
0690ef
 	if (optind != argc - 1)
0690ef
 		return command_usage(&open_cmd);
0690ef
 
0690ef
+	if ((flags & (IO_READONLY|IO_TMPFILE)) == (IO_READONLY|IO_TMPFILE)) {
0690ef
+		fprintf(stderr, _("-T and -r options are incompatible\n"));
0690ef
+		return -1;
0690ef
+	}
0690ef
+
0690ef
 	fd = openfile(argv[optind], &geometry, flags, mode);
0690ef
 	if (fd < 0)
0690ef
 		return 0;
0690ef
@@ -731,7 +760,7 @@ open_init(void)
0690ef
 	open_cmd.argmin = 0;
0690ef
 	open_cmd.argmax = -1;
0690ef
 	open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
0690ef
-	open_cmd.args = _("[-acdrstx] [path]");
0690ef
+	open_cmd.args = _("[-acdrstxT] [path]");
0690ef
 	open_cmd.oneline = _("open the file specified by path");
0690ef
 	open_cmd.help = open_help;
0690ef
 
0690ef
diff --git a/io/prealloc.c b/io/prealloc.c
0690ef
index 8380646..aba6b44 100644
0690ef
--- a/io/prealloc.c
0690ef
+++ b/io/prealloc.c
0690ef
@@ -29,6 +29,14 @@
0690ef
 #define FALLOC_FL_PUNCH_HOLE	0x02
0690ef
 #endif
0690ef
 
0690ef
+#ifndef FALLOC_FL_COLLAPSE_RANGE
0690ef
+#define FALLOC_FL_COLLAPSE_RANGE 0x08
0690ef
+#endif
0690ef
+
0690ef
+#ifndef FALLOC_FL_ZERO_RANGE
0690ef
+#define FALLOC_FL_ZERO_RANGE 0x10
0690ef
+#endif
0690ef
+
0690ef
 static cmdinfo_t allocsp_cmd;
0690ef
 static cmdinfo_t freesp_cmd;
0690ef
 static cmdinfo_t resvsp_cmd;
0690ef
@@ -37,6 +45,8 @@ static cmdinfo_t zero_cmd;
0690ef
 #if defined(HAVE_FALLOCATE)
0690ef
 static cmdinfo_t falloc_cmd;
0690ef
 static cmdinfo_t fpunch_cmd;
0690ef
+static cmdinfo_t fcollapse_cmd;
0690ef
+static cmdinfo_t fzero_cmd;
0690ef
 #endif
0690ef
 
0690ef
 static int
0690ef
@@ -159,8 +169,11 @@ fallocate_f(
0690ef
 	int		mode = 0;
0690ef
 	int		c;
0690ef
 
0690ef
-	while ((c = getopt(argc, argv, "kp")) != EOF) {
0690ef
+	while ((c = getopt(argc, argv, "ckp")) != EOF) {
0690ef
 		switch (c) {
0690ef
+		case 'c':
0690ef
+			mode = FALLOC_FL_COLLAPSE_RANGE;
0690ef
+			break;
0690ef
 		case 'k':
0690ef
 			mode = FALLOC_FL_KEEP_SIZE;
0690ef
 			break;
0690ef
@@ -203,6 +216,50 @@ fpunch_f(
0690ef
 	}
0690ef
 	return 0;
0690ef
 }
0690ef
+
0690ef
+static int
0690ef
+fcollapse_f(
0690ef
+	int		argc,
0690ef
+	char		**argv)
0690ef
+{
0690ef
+	xfs_flock64_t	segment;
0690ef
+	int		mode = FALLOC_FL_COLLAPSE_RANGE;
0690ef
+
0690ef
+	if (!offset_length(argv[1], argv[2], &segment))
0690ef
+		return 0;
0690ef
+
0690ef
+	if (fallocate(file->fd, mode,
0690ef
+			segment.l_start, segment.l_len)) {
0690ef
+		perror("fallocate");
0690ef
+		return 0;
0690ef
+	}
0690ef
+	return 0;
0690ef
+}
0690ef
+
0690ef
+static int
0690ef
+fzero_f(
0690ef
+	int		argc,
0690ef
+	char		**argv)
0690ef
+{
0690ef
+	xfs_flock64_t	segment;
0690ef
+	int		mode = FALLOC_FL_ZERO_RANGE;
0690ef
+	int		index = 1;
0690ef
+
0690ef
+	if (strncmp(argv[index], "-k", 3) == 0) {
0690ef
+		mode |= FALLOC_FL_KEEP_SIZE;
0690ef
+		index++;
0690ef
+	}
0690ef
+
0690ef
+	if (!offset_length(argv[index], argv[index + 1], &segment))
0690ef
+		return 0;
0690ef
+
0690ef
+	if (fallocate(file->fd, mode,
0690ef
+			segment.l_start, segment.l_len)) {
0690ef
+		perror("fallocate");
0690ef
+		return 0;
0690ef
+	}
0690ef
+	return 0;
0690ef
+}
0690ef
 #endif	/* HAVE_FALLOCATE */
0690ef
 
0690ef
 void
0690ef
@@ -263,9 +320,9 @@ prealloc_init(void)
0690ef
 	falloc_cmd.argmin = 2;
0690ef
 	falloc_cmd.argmax = -1;
0690ef
 	falloc_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
0690ef
-	falloc_cmd.args = _("[-k] [-p] off len");
0690ef
+	falloc_cmd.args = _("[-c] [-k] [-p] off len");
0690ef
 	falloc_cmd.oneline =
0690ef
-		_("allocates space associated with part of a file via fallocate");
0690ef
+	_("allocates space associated with part of a file via fallocate");
0690ef
 	add_command(&falloc_cmd);
0690ef
 
0690ef
 	fpunch_cmd.name = "fpunch";
0690ef
@@ -275,7 +332,27 @@ prealloc_init(void)
0690ef
 	fpunch_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
0690ef
 	fpunch_cmd.args = _("off len");
0690ef
 	fpunch_cmd.oneline =
0690ef
-		_("de-allocates space assocated with part of a file via fallocate");
0690ef
+	_("de-allocates space assocated with part of a file via fallocate");
0690ef
 	add_command(&fpunch_cmd);
0690ef
+
0690ef
+	fcollapse_cmd.name = "fcollapse";
0690ef
+	fcollapse_cmd.cfunc = fcollapse_f;
0690ef
+	fcollapse_cmd.argmin = 2;
0690ef
+	fcollapse_cmd.argmax = 2;
0690ef
+	fcollapse_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
0690ef
+	fcollapse_cmd.args = _("off len");
0690ef
+	fcollapse_cmd.oneline =
0690ef
+	_("de-allocates space and eliminates the hole by shifting extents");
0690ef
+	add_command(&fcollapse_cmd);
0690ef
+
0690ef
+	fzero_cmd.name = "fzero";
0690ef
+	fzero_cmd.cfunc = fzero_f;
0690ef
+	fzero_cmd.argmin = 2;
0690ef
+	fzero_cmd.argmax = 3;
0690ef
+	fzero_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
0690ef
+	fzero_cmd.args = _("[-k] off len");
0690ef
+	fzero_cmd.oneline =
0690ef
+	_("zeroes space and eliminates holes by preallocating");
0690ef
+	add_command(&fzero_cmd);
0690ef
 #endif	/* HAVE_FALLOCATE */
0690ef
 }
0690ef
diff --git a/libxfs/cache.c b/libxfs/cache.c
0690ef
index 84d2860..dc69689 100644
0690ef
--- a/libxfs/cache.c
0690ef
+++ b/libxfs/cache.c
0690ef
@@ -25,6 +25,7 @@
0690ef
 #include <xfs/platform_defs.h>
0690ef
 #include <xfs/list.h>
0690ef
 #include <xfs/cache.h>
0690ef
+#include <xfs/libxfs.h>
0690ef
 
0690ef
 #define CACHE_DEBUG 1
0690ef
 #undef CACHE_DEBUG
0690ef
@@ -61,6 +62,7 @@ cache_init(
0690ef
 	cache->c_misses = 0;
0690ef
 	cache->c_maxcount = maxcount;
0690ef
 	cache->c_hashsize = hashsize;
0690ef
+	cache->c_hashshift = libxfs_highbit32(hashsize);
0690ef
 	cache->hash = cache_operations->hash;
0690ef
 	cache->alloc = cache_operations->alloc;
0690ef
 	cache->flush = cache_operations->flush;
0690ef
@@ -343,7 +345,7 @@ cache_node_get(
0690ef
 	int			priority = 0;
0690ef
 	int			purged = 0;
0690ef
 
0690ef
-	hashidx = cache->hash(key, cache->c_hashsize);
0690ef
+	hashidx = cache->hash(key, cache->c_hashsize, cache->c_hashshift);
0690ef
 	hash = cache->c_hash + hashidx;
0690ef
 	head = &hash->ch_list;
0690ef
 
0690ef
@@ -515,7 +517,8 @@ cache_node_purge(
0690ef
 	struct cache_hash *	hash;
0690ef
 	int			count = -1;
0690ef
 
0690ef
-	hash = cache->c_hash + cache->hash(key, cache->c_hashsize);
0690ef
+	hash = cache->c_hash + cache->hash(key, cache->c_hashsize,
0690ef
+					   cache->c_hashshift);
0690ef
 	head = &hash->ch_list;
0690ef
 	pthread_mutex_lock(&hash->ch_mutex);
0690ef
 	for (pos = head->next, n = pos->next; pos != head;
0690ef
diff --git a/libxfs/init.h b/libxfs/init.h
0690ef
index f0b8cb6..112febb 100644
0690ef
--- a/libxfs/init.h
0690ef
+++ b/libxfs/init.h
0690ef
@@ -31,7 +31,6 @@ extern char *platform_findrawpath (char *path);
0690ef
 extern char *platform_findblockpath (char *path);
0690ef
 extern int platform_direct_blockdev (void);
0690ef
 extern int platform_align_blockdev (void);
0690ef
-extern int platform_nproc(void);
0690ef
 extern unsigned long platform_physmem(void);	/* in kilobytes */
0690ef
 extern int platform_has_uuid;
0690ef
 
0690ef
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
0690ef
index 0219a08..1b691fb 100644
0690ef
--- a/libxfs/rdwr.c
0690ef
+++ b/libxfs/rdwr.c
0690ef
@@ -203,7 +203,8 @@ xfs_buf_t	*libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *,
0690ef
 				int, int, const struct xfs_buf_ops *);
0690ef
 int		libxfs_writebuf(xfs_buf_t *, int);
0690ef
 xfs_buf_t	*libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int);
0690ef
-xfs_buf_t	*libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int);
0690ef
+xfs_buf_t	*libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *,
0690ef
+				int, int);
0690ef
 xfs_buf_t	*libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int,
0690ef
 				unsigned int);
0690ef
 void		libxfs_putbuf (xfs_buf_t *);
0690ef
@@ -255,9 +256,10 @@ libxfs_trace_getbuf(const char *func, const char *file, int line,
0690ef
 
0690ef
 xfs_buf_t *
0690ef
 libxfs_trace_getbuf_map(const char *func, const char *file, int line,
0690ef