gfs2-utils: master - fsck.gfs2: re-read hash table if directory height or depth changes

Bob Peterson rpeterso at fedoraproject.org
Mon May 20 16:18:00 UTC 2013


Gitweb:        http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=46cce9dc2161fc83d3f5a35b6c12a6a0a0dc6b3f
Commit:        46cce9dc2161fc83d3f5a35b6c12a6a0a0dc6b3f
Parent:        5d6bf12f59b07e9eb6e926408b21b5ba49132522
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Thu Mar 7 13:58:18 2013 -0700
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Mon May 20 11:12:46 2013 -0500

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.
---
 gfs2/fsck/metawalk.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 5bcac77..2e998df 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);


More information about the cluster-commits mailing list