cluster: STABLE3 - fsck.gfs2: metawalk was not checking many directories

Bob Peterson rpeterso at fedoraproject.org
Tue Jan 26 21:20:32 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=611c213c35e1af8dc36f3b15fccc5ee5c352eaa3
Commit:        611c213c35e1af8dc36f3b15fccc5ee5c352eaa3
Parent:        013d20413ffb8d960089836be487b9c16a9f12d6
Author:        Bob Peterson <bob at ganesha.peterson>
AuthorDate:    Fri Jan 22 14:24:31 2010 -0600
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Tue Jan 26 14:39:31 2010 -0600

fsck.gfs2: metawalk was not checking many directories

The fsck.gfs2 program was not checking the directory hash tables
of many subdirectories.  It was checking the leaf blocks, but
it wasn't checking the hash table block pointers if the height
value was equal to 0, which means every directory with a small
number of leaf blocks.  That means before, you could have all
kinds of directory corruption and never know it.

rhbz#455300
---
 gfs2/fsck/metawalk.c |   70 +++++++++++++++++++++++++++----------------------
 1 files changed, 39 insertions(+), 31 deletions(-)

diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index a0ca65b..13290e1 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1070,12 +1070,24 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
 	uint32_t height = ip->i_di.di_height;
 	struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
 	osi_list_t *prev_list, *cur_list, *tmp;
-	int i, head_size;
+	int i, head_size, iblk_type;
 	uint64_t *ptr, block;
-	int err;
+	int error = 0, err;
 
 	osi_list_add(&metabh->b_altlist, &mlp[0]);
 
+	/* Directories are special.  Their 'data' is the hash table, which is
+	   basically an indirect block list. Their height is not important
+	   because it checks everything through the hash table using
+	   "depth" field calculations. However, we still have to check the
+	   indirect blocks, even if the height == 1.  */
+	if (S_ISDIR(ip->i_di.di_mode)) {
+		height++;
+		iblk_type = GFS2_METATYPE_JD;
+	} else {
+		iblk_type = GFS2_METATYPE_IN;
+	}
+
 	/* if(<there are no indirect blocks to check>) */
 	if (height < 2)
 		return 0;
@@ -1089,7 +1101,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
 
 			if (i > 1) {
 				/* if this isn't really a block list skip it */
-				if (gfs2_check_meta(bh, GFS2_METATYPE_IN))
+				if (gfs2_check_meta(bh, iblk_type))
 					continue;
 				head_size = sizeof(struct gfs2_meta_header);
 			} else {
@@ -1114,9 +1126,12 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
 				   it gets with "bread". */
 				if(err < 0) {
 					stack;
+					error = err;
 					goto fail;
 				}
 				if(err > 0) {
+					if (!error)
+						error = err;
 					log_debug( _("Skipping block %" PRIu64
 						     " (0x%" PRIx64 ")\n"),
 						   block, block);
@@ -1135,10 +1150,10 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
 			} /* for all data on the indirect block */
 		} /* for blocks at that height */
 	} /* for height */
-	return 0;
+	return error;
 fail:
 	free_metalist(ip, mlp);
-	return -1;
+	return error;
 }
 
 /**
@@ -1156,26 +1171,32 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 	uint32_t height = ip->i_di.di_height;
 	int  i, head_size;
 	uint64_t blks_checked = 0;
-	int error = 0;
+	int error;
 
-	if (!height)
-		goto end;
+	if (!height && !S_ISDIR(ip->i_di.di_mode))
+		return 0;
 
 	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
 		osi_list_init(&metalist[i]);
 
-	/* create metalist for each level */
-	if (build_and_check_metalist(ip, &metalist[0], pass)){
+	/* create and check the metadata list for each height */
+	error = build_and_check_metalist(ip, &metalist[0], pass);
+	if (error) {
 		stack;
-		return -1;
+		return error;
 	}
 
-	/* We don't need to record directory blocks - they will be
-	 * recorded later...i think... */
-        if (S_ISDIR(ip->i_di.di_mode))
-		log_debug( _("Directory with height > 0 at %llu (0x%llx)\n"),
-			  (unsigned long long)ip->i_di.di_num.no_addr,
-			  (unsigned long long)ip->i_di.di_num.no_addr);
+	/* For directories, we've already checked the "data" blocks which
+	 * comprise the directory hash table, so we perform the directory
+	 * checks and exit. */
+        if (S_ISDIR(ip->i_di.di_mode)) {
+		free_metalist(ip, &metalist[0]);
+		if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
+			return 0;
+		/* check validity of leaf blocks and leaf chains */
+		error = check_leaf_blks(ip, pass);
+		return error;
+	}
 
 	/* check data blocks */
 	list = &metalist[height - 1];
@@ -1236,20 +1257,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 			    (unsigned long long)ip->i_di.di_num.no_addr);
 		fflush(stdout);
 	}
-
-end:
-        if (S_ISDIR(ip->i_di.di_mode)) {
-		/* check validity of leaf blocks and leaf chains */
-		if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
-			error = check_leaf_blks(ip, pass);
-			if(error < 0)
-				return -1;
-			if(error > 0)
-				return 1;
-		}
-	}
-
-	return 0;
+	return error;
 }
 
 /* Checks stuffed inode directories */


More information about the cluster-commits mailing list