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

[Cluster-devel] [gfs2-utils PATCH 15/47] fsck.gfs2: re-read hash table if directory height or depth changes



There may be times when fsck.gfs2 wants to move things around. For
example, if it finds dirents entries on the wrong leaf block, it
may want to move them to a different leaf. If it does, it may need
to split the leaf, which means we're adding another block. We may
in fact have doubled our exhash table, so the table in cache is no
longer valid. In this case, we need to discard the old one and read
it in again. This patch checks for these things and re-reads the
hash table as appropriate.

rhbz#902920
---
 gfs2/fsck/metawalk.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 40ef766..73bdba0 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -683,18 +683,23 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 	struct gfs2_leaf leaf, oldleaf;
 	unsigned hsize = (1 << ip->i_di.di_depth);
 	uint64_t leaf_no, old_leaf, bad_leaf = -1;
-	uint64_t first_ok_leaf;
+	uint64_t first_ok_leaf, orig_di_blocks;
 	struct gfs2_buffer_head *lbh;
 	int lindex;
 	struct gfs2_sbd *sdp = ip->i_sbd;
-	int ref_count = 0, old_was_dup;
+	int ref_count = 0, orig_ref_count, orig_di_depth, orig_di_height, old_was_dup;
 	uint64_t *tbl;
+	int tbl_valid;
 
 	tbl = get_dir_hash(ip);
 	if (tbl == NULL) {
 		perror("get_dir_hash");
 		return -1;
 	}
+	tbl_valid = 1;
+	orig_di_depth = ip->i_di.di_depth;
+	orig_di_height = ip->i_di.di_height;
+	orig_di_blocks = ip->i_di.di_blocks;
 
 	/* Turn off system readahead */
 	posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_RANDOM);
@@ -752,6 +757,21 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 	for (lindex = 0; lindex < hsize; lindex++) {
 		if (fsck_abort)
 			break;
+
+		if (!tbl_valid) {
+			free(tbl);
+			log_debug(_("Re-reading 0x%llx hash table.\n"),
+				  (unsigned long long)ip->i_di.di_num.no_addr);
+			tbl = get_dir_hash(ip);
+			if (tbl == NULL) {
+				perror("get_dir_hash");
+				return -1;
+			}
+			tbl_valid = 1;
+			orig_di_depth = ip->i_di.di_depth;
+			orig_di_height = ip->i_di.di_height;
+			orig_di_blocks = ip->i_di.di_blocks;
+		}
 		leaf_no = be64_to_cpu(tbl[lindex]);
 
 		/* GFS has multiple indirect pointers to the same leaf
@@ -765,6 +785,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 			ref_count++;
 			continue;
 		}
+		orig_ref_count = ref_count;
 
 		do {
 			if (fsck_abort) {
@@ -775,6 +796,8 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 			error = check_leaf(ip, lindex, pass, &ref_count,
 					   &leaf_no, old_leaf, &bad_leaf,
 					   first_ok_leaf, &leaf, &oldleaf);
+			if (ref_count != orig_ref_count)
+				tbl_valid = 0;
 			old_was_dup = (error == -EEXIST);
 			old_leaf = leaf_no;
 			memcpy(&oldleaf, &leaf, sizeof(oldleaf));
@@ -784,6 +807,28 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 			log_debug( _("Leaf chain (0x%llx) detected.\n"),
 				   (unsigned long long)leaf_no);
 		} while (1); /* while we have chained leaf blocks */
+		if (orig_di_depth != ip->i_di.di_depth) {
+			log_debug(_("Depth of 0x%llx changed from %d to %d\n"),
+				  (unsigned long long)ip->i_di.di_num.no_addr,
+				  orig_di_depth, ip->i_di.di_depth);
+			tbl_valid = 0;
+		}
+		if (orig_di_height != ip->i_di.di_height) {
+			log_debug(_("Height of 0x%llx changed from %d to "
+				    "%d\n"),
+				  (unsigned long long)ip->i_di.di_num.no_addr,
+				  orig_di_height, ip->i_di.di_height);
+			tbl_valid = 0;
+		}
+		if (orig_di_blocks != ip->i_di.di_blocks) {
+			log_debug(_("Block count of 0x%llx changed from %llu "
+				    "to %llu\n"),
+				  (unsigned long long)ip->i_di.di_num.no_addr,
+				  (unsigned long long)orig_di_blocks,
+				  (unsigned long long)ip->i_di.di_blocks);
+			tbl_valid = 0;
+		}
+		lindex += ref_count;
 	} /* for every leaf block */
 	free(tbl);
 	posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
-- 
1.7.11.7


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