[PATCH 5/5] metadump: fully support discontiguous directory blocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Dave Chinner <dchinner@xxxxxxxxxx>

Now that directory block obfuscation can handle single contiguous
directory blocks, we can make the multi-block code use discontiguous
buffers to read in an entire directory block at a time. This allows
us to pass a complete directory object to the processing function
and hence be able to process any sort of directory object regardless
of it's underlying layout.

With the, we can remove the multi-block loop from the directory
processing code and get rid of allt eh structures used to hold
inter-call state. This graeatly simplifies the code as well as
adding the additional functionality.

With this patch, a CRC enabled filesystem now passes xfs/291.

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 db/metadump.c | 280 ++++++++++++++++++++++++++++------------------------------
 1 file changed, 133 insertions(+), 147 deletions(-)

diff --git a/db/metadump.c b/db/metadump.c
index e973c5e..6ed392b 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -1111,24 +1111,11 @@ obfuscate_sf_attr(
 	}
 }
 
-/*
- * dir_data structure is used to track multi-fsblock dir2 blocks between extent
- * processing calls.
- */
-
-static struct dir_data_s {
-	int			end_of_data;
-	int			block_index;
-	int			offset_to_entry;
-	int			bad_block;
-} dir_data;
-
 static void
-obfuscate_dir_data_blocks(
-	char			*block,
-	xfs_dfiloff_t		offset,
-	xfs_dfilblks_t		count,
-	int			is_block_format)
+obfuscate_dir_data_block(
+	char		*block,
+	xfs_dfiloff_t	offset,
+	int		is_block_format)
 {
 	/*
 	 * we have to rely on the fileoffset and signature of the block to
@@ -1136,123 +1123,96 @@ obfuscate_dir_data_blocks(
 	 * for multi-fsblock dir blocks, if a name crosses an extent boundary,
 	 * ignore it and continue.
 	 */
-	int			c;
-	int			dir_offset;
-	char			*ptr;
-	char			*endptr;
-
-	if (is_block_format && count != mp->m_dirblkfsbs)
-		return; /* too complex to handle this rare case */
-
-	for (c = 0, endptr = block; c < count; c++) {
-
-		if (dir_data.block_index == 0) {
-			int		wantmagic;
-			struct xfs_dir2_data_hdr *datahdr;
-
-			datahdr = (struct xfs_dir2_data_hdr *)block;
-
-			if (offset % mp->m_dirblkfsbs != 0)
-				return;	/* corrupted, leave it alone */
-
-			dir_data.bad_block = 0;
-
-			if (is_block_format) {
-				xfs_dir2_leaf_entry_t	*blp;
-				xfs_dir2_block_tail_t	*btp;
-
-				btp = xfs_dir2_block_tail_p(mp, datahdr);
-				blp = xfs_dir2_block_leaf_p(btp);
-				if ((char *)blp > (char *)btp)
-					blp = (xfs_dir2_leaf_entry_t *)btp;
-
-				dir_data.end_of_data = (char *)blp - block;
-				wantmagic = XFS_DIR2_BLOCK_MAGIC;
-			} else { /* leaf/node format */
-				dir_data.end_of_data = mp->m_dirblkfsbs <<
-						mp->m_sb.sb_blocklog;
-				wantmagic = XFS_DIR2_DATA_MAGIC;
-			}
-			dir_data.offset_to_entry =
-					xfs_dir3_data_entry_offset(datahdr);
-
-			if (be32_to_cpu(datahdr->magic) != wantmagic) {
-				if (show_warnings)
-					print_warning("invalid magic in dir "
-						"inode %llu block %ld",
-						(long long)cur_ino,
-						(long)offset);
-				dir_data.bad_block = 1;
-			}
-		}
-		dir_data.block_index++;
-		if (dir_data.block_index == mp->m_dirblkfsbs)
-			dir_data.block_index = 0;
+	int		dir_offset;
+	char		*ptr;
+	char		*endptr;
+	int		end_of_data;
+	int		wantmagic;
+	struct xfs_dir2_data_hdr *datahdr;
+
+	datahdr = (struct xfs_dir2_data_hdr *)block;
+
+	if (offset % mp->m_dirblkfsbs != 0)
+		return;	/* corrupted, leave it alone */
+
+	if (is_block_format) {
+		xfs_dir2_leaf_entry_t	*blp;
+		xfs_dir2_block_tail_t	*btp;
+
+		btp = xfs_dir2_block_tail_p(mp, datahdr);
+		blp = xfs_dir2_block_leaf_p(btp);
+		if ((char *)blp > (char *)btp)
+			blp = (xfs_dir2_leaf_entry_t *)btp;
+
+		end_of_data = (char *)blp - block;
+		if (xfs_sb_version_hascrc(&mp->m_sb))
+			wantmagic = XFS_DIR3_BLOCK_MAGIC;
+		else
+			wantmagic = XFS_DIR2_BLOCK_MAGIC;
+	} else { /* leaf/node format */
+		end_of_data = mp->m_dirblkfsbs << mp->m_sb.sb_blocklog;
+		if (xfs_sb_version_hascrc(&mp->m_sb))
+			wantmagic = XFS_DIR3_DATA_MAGIC;
+		else
+			wantmagic = XFS_DIR2_DATA_MAGIC;
+	}
+
+	if (be32_to_cpu(datahdr->magic) != wantmagic) {
+		if (show_warnings)
+			print_warning(
+		"invalid magic in dir inode %llu block %ld",
+					(long long)cur_ino, (long)offset);
+		return;
+	}
 
-		if (dir_data.bad_block)
-			continue;
+	dir_offset = xfs_dir3_data_entry_offset(datahdr);
+	ptr = block + dir_offset;
+	endptr = block + mp->m_sb.sb_blocksize;
 
-		dir_offset = (dir_data.block_index << mp->m_sb.sb_blocklog) +
-				dir_data.offset_to_entry;
-
-		ptr = endptr + dir_data.offset_to_entry;
-		endptr += mp->m_sb.sb_blocksize;
-
-		while (ptr < endptr && dir_offset < dir_data.end_of_data) {
-			xfs_dir2_data_entry_t	*dep;
-			xfs_dir2_data_unused_t	*dup;
-			int			length;
-
-			dup = (xfs_dir2_data_unused_t *)ptr;
-
-			if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-				int	length = be16_to_cpu(dup->length);
-				if (dir_offset + length > dir_data.end_of_data ||
-						length == 0 || (length &
-						 (XFS_DIR2_DATA_ALIGN - 1))) {
-					if (show_warnings)
-						print_warning("invalid length "
-							"for dir free space in "
-							"inode %llu",
-							(long long)cur_ino);
-					dir_data.bad_block = 1;
-					break;
-				}
-				if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
-						dir_offset) {
-					dir_data.bad_block = 1;
-					break;
-				}
-				dir_offset += length;
-				ptr += length;
-				if (dir_offset >= dir_data.end_of_data ||
-						ptr >= endptr)
-					break;
-			}
+	while (ptr < endptr && dir_offset < end_of_data) {
+		xfs_dir2_data_entry_t	*dep;
+		xfs_dir2_data_unused_t	*dup;
+		int			length;
 
-			dep = (xfs_dir2_data_entry_t *)ptr;
-			length = xfs_dir3_data_entsize(mp, dep->namelen);
+		dup = (xfs_dir2_data_unused_t *)ptr;
 
-			if (dir_offset + length > dir_data.end_of_data ||
-					ptr + length > endptr) {
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+			int	length = be16_to_cpu(dup->length);
+			if (dir_offset + length > end_of_data ||
+			    !length || (length & (XFS_DIR2_DATA_ALIGN - 1))) {
 				if (show_warnings)
-					print_warning("invalid length for "
-						"dir entry name in inode %llu",
+					print_warning(
+			"invalid length for dir free space in inode %llu",
 						(long long)cur_ino);
-				break;
-			}
-			if (be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) !=
-					dir_offset) {
-				dir_data.bad_block = 1;
-				break;
+				return;
 			}
-			generate_obfuscated_name(be64_to_cpu(dep->inumber),
-					dep->namelen, &dep->name[0]);
+			if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) !=
+					dir_offset)
+				return;
 			dir_offset += length;
 			ptr += length;
+			if (dir_offset >= end_of_data || ptr >= endptr)
+				return;
+		}
+
+		dep = (xfs_dir2_data_entry_t *)ptr;
+		length = xfs_dir3_data_entsize(mp, dep->namelen);
+
+		if (dir_offset + length > end_of_data ||
+		    ptr + length > endptr) {
+			if (show_warnings)
+				print_warning(
+			"invalid length for dir entry name in inode %llu",
+					(long long)cur_ino);
+			return;
 		}
-		dir_data.offset_to_entry = dir_offset &
-						(mp->m_sb.sb_blocksize - 1);
+		if (be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) !=
+				dir_offset)
+			return;
+		generate_obfuscated_name(be64_to_cpu(dep->inumber),
+					 dep->namelen, &dep->name[0]);
+		dir_offset += length;
+		ptr += length;
 	}
 }
 
@@ -1399,8 +1359,8 @@ process_single_fsb_objects(
 			if (o >= mp->m_dirleafblk)
 				break;
 
-			obfuscate_dir_data_blocks(dp, o, 1,
-						  last == mp->m_dirblkfsbs);
+			obfuscate_dir_data_block(dp, o,
+						 last == mp->m_dirblkfsbs);
 			break;
 		case TYP_SYMLINK:
 			obfuscate_symlink_block(dp);
@@ -1421,6 +1381,12 @@ out_pop:
 	return ret;
 }
 
+/*
+ * Static map to aggregate multiple extents into a single directory block.
+ */
+static struct bbmap mfsb_map;
+static int mfsb_length;
+
 static int
 process_multi_fsb_objects(
 	xfs_dfiloff_t	o,
@@ -1436,33 +1402,54 @@ process_multi_fsb_objects(
 		return -EINVAL;
 	}
 
-	push_cur();
-	set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), c * blkbb,
-			DB_RING_IGN, NULL);
+	while (c > 0) {
+		unsigned int	bm_len;
 
-	if (!iocur_top->data) {
-		xfs_agnumber_t	agno = XFS_FSB_TO_AGNO(mp, s);
-		xfs_agblock_t	agbno = XFS_FSB_TO_AGBNO(mp, s);
+		if (mfsb_length + c >= mp->m_dirblkfsbs) {
+			bm_len = mp->m_dirblkfsbs - mfsb_length;
+			mfsb_length = 0;
+		} else {
+			mfsb_length += c;
+			bm_len = c;
+		}
 
-		print_warning("cannot read %s block %u/%u (%llu)",
-				typtab[btype].name, agno, agbno, s);
-		if (stop_on_read_error)
-			ret = -EIO;
-		goto out_pop;
+		mfsb_map.b[mfsb_map.nmaps].bm_bn = XFS_FSB_TO_DADDR(mp, s);
+		mfsb_map.b[mfsb_map.nmaps].bm_len = XFS_FSB_TO_BB(mp, bm_len);
+		mfsb_map.nmaps++;
 
-	}
+		if (mfsb_length == 0) {
+			push_cur();
+			set_cur(&typtab[btype], 0, 0, DB_RING_IGN, &mfsb_map);
+			if (!iocur_top->data) {
+				xfs_agnumber_t	agno = XFS_FSB_TO_AGNO(mp, s);
+				xfs_agblock_t	agbno = XFS_FSB_TO_AGBNO(mp, s);
 
-	if (dont_obfuscate || o >= mp->m_dirleafblk) {
-		ret = write_buf(iocur_top);
-		goto out_pop;
-	}
+				print_warning("cannot read %s block %u/%u (%llu)",
+						typtab[btype].name, agno, agbno, s);
+				if (stop_on_read_error)
+					ret = -1;
+				goto out_pop;
 
-	obfuscate_dir_data_blocks(iocur_top->data, o, c,
-				 last == mp->m_dirblkfsbs);
-	ret = write_buf(iocur_top);
+			}
 
+			if (dont_obfuscate || o >= mp->m_dirleafblk) {
+				ret = write_buf(iocur_top);
+				goto out_pop;
+			}
+
+			obfuscate_dir_data_block(iocur_top->data, o,
+						  last == mp->m_dirblkfsbs);
+			ret = write_buf(iocur_top);
 out_pop:
-	pop_cur();
+			pop_cur();
+			mfsb_map.nmaps = 0;
+			if (ret)
+				break;
+		}
+		c -= bm_len;
+		s += bm_len;
+	}
+
 	return ret;
 }
 
@@ -1750,7 +1737,6 @@ process_inode(
 	/* copy appropriate data fork metadata */
 	switch (be16_to_cpu(dip->di_mode) & S_IFMT) {
 		case S_IFDIR:
-			memset(&dir_data, 0, sizeof(dir_data));
 			success = process_inode_data(dip, TYP_DIR2);
 			break;
 		case S_IFLNK:
-- 
1.8.4.rc3

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux