[Cluster-devel] cluster/gfs2 fsck/metawalk.c libgfs2/libgfs2.h ...

rpeterso at sourceware.org rpeterso at sourceware.org
Sun Sep 16 17:19:04 UTC 2007


CVSROOT:	/cvs/cluster
Module name:	cluster
Branch: 	RHEL51
Changes by:	rpeterso at sourceware.org	2007-09-16 17:19:03

Modified files:
	gfs2/fsck      : metawalk.c 
	gfs2/libgfs2   : libgfs2.h structures.c 

Log message:
	Resolves: bz 287901: GFS2: fsck errors and corruption with files > 945MB
	
	The gfs2_fsck program wasn't following enough levels of indirection
	when walking metadata.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/metawalk.c.diff?cvsroot=cluster&only_with_tag=RHEL51&r1=1.3.2.7&r2=1.3.2.7.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/libgfs2.h.diff?cvsroot=cluster&only_with_tag=RHEL51&r1=1.7.2.9&r2=1.7.2.9.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/structures.c.diff?cvsroot=cluster&only_with_tag=RHEL51&r1=1.5.2.5&r2=1.5.2.5.2.1

--- cluster/gfs2/fsck/metawalk.c	2007/06/28 23:42:45	1.3.2.7
+++ cluster/gfs2/fsck/metawalk.c	2007/09/16 17:19:03	1.3.2.7.2.1
@@ -543,79 +543,81 @@
  * @mlp:
  */
 static int build_and_check_metalist(struct gfs2_inode *ip,
-									struct metawalk_fxns *pass)
+				    osi_list_t *mlp,
+				    struct metawalk_fxns *pass)
 {
 	uint32_t height = ip->i_di.di_height;
-	struct gfs2_buffer_head *nbh, *metabh;
-	int head_size;
+	struct gfs2_buffer_head *bh, *nbh, *metabh;
+	osi_list_t *prev_list, *cur_list, *tmp;
+	int i, head_size;
 	uint64_t *ptr, block;
 	int err;
 
 	metabh = bread(ip->i_sbd, ip->i_di.di_num.no_addr);
 
+	osi_list_add(&metabh->b_altlist, &mlp[0]);
+
 	/* if(<there are no indirect blocks to check>) */
-	if (height < 1) {
+	if (height < 2) {
 		brelse(metabh, not_updated);
 		return 0;
 	}
-	head_size = sizeof(struct gfs2_dinode);
-	for (ptr = (uint64_t *)(metabh->b_data + head_size);
-		 (char *)ptr < (metabh->b_data + metabh->b_size); ptr++) {
-		nbh = NULL;
+	for (i = 1; i < height; i++){
+		prev_list = &mlp[i - 1];
+		cur_list = &mlp[i];
+
+		for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
+			bh = osi_list_entry(tmp, struct gfs2_buffer_head,
+					    b_altlist);
+
+			head_size = (i > 1 ?
+				     sizeof(struct gfs2_meta_header) :
+				     sizeof(struct gfs2_dinode));
+
+			for (ptr = (uint64_t *)(bh->b_data + head_size);
+			     (char *)ptr < (bh->b_data + bh->b_size);
+			     ptr++) {
+				nbh = NULL;
 		
-		if (!*ptr)
-			continue;
+				if (!*ptr)
+					continue;
 
-		block = be64_to_cpu(*ptr);
-		if (height > 1) {
-			uint64_t *subptr, subblock, prevsubblock;
-			int head_size2;
-			struct gfs2_buffer_head *nbh2;
-			
-			nbh2 = NULL;
-			prevsubblock = 0;
-			head_size2 = sizeof(struct gfs2_meta_header);
-			err = pass->check_metalist(ip, block, &nbh, pass->private);
-			if (!nbh)
-				nbh = nbh2 = bread(ip->i_sbd, block);
-			for (subptr = (uint64_t *)(nbh->b_data + head_size2);
-				 (char *)subptr < (nbh->b_data + nbh->b_size);
-				 subptr++) {
+				block = be64_to_cpu(*ptr);
+				err = pass->check_metalist(ip, block, &nbh,
+							   pass->private);
 				if(err < 0) {
 					stack;
 					goto fail;
 				}
 				if(err > 0) {
-					log_debug("Skipping block %" PRIu64 " (0x%" PRIx64 ")\n",
-							  block, block);
+					log_debug("Skipping block %" PRIu64
+						  " (0x%" PRIx64 ")\n",
+						  block, block);
 					continue;
 				}
-				subblock = be64_to_cpu(*subptr);
-				if (subblock) {
-					if (subblock != prevsubblock) {
-						prevsubblock = subblock;
-						if(pass->check_data &&
-						   (pass->check_data(ip, subblock,
-											 pass->private) < 0)) {
-							stack;
-							return -1;
-						}
-					} /* if different than the previous block */
-				} /* if non-zero indirect block pointer */
+				if(!nbh) {
+					nbh = bread(ip->i_sbd, block);
+					osi_list_add(&nbh->b_altlist, cur_list);
+				}
+				else
+					osi_list_add(&nbh->b_altlist, cur_list);
 			} /* for all data on the indirect block */
-			if (nbh2)
-				brelse(nbh2, not_updated);
-		} /* if height */
-		else if(pass->check_data &&
-				(pass->check_data(ip, block, pass->private) < 0)) {
-			stack;
-			brelse(metabh, not_updated);
-			return -1;
-		}
-	} /* for all level 1 pointers */
-fail:
+		} /* for blocks at that height */
+	} /* for height */
 	brelse(metabh, not_updated);
 	return 0;
+fail:
+	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
+		osi_list_t *list;
+		list = &mlp[i];
+		while (!osi_list_empty(list)) {
+			nbh = osi_list_entry(list->next,
+					     struct gfs2_buffer_head, b_altlist);
+			osi_list_del(&nbh->b_altlist);
+		}
+	}
+	brelse(metabh, not_updated);
+	return -1;
 }
 
 /**
@@ -626,18 +628,71 @@
  */
 int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 {
+	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
+	osi_list_t *list, *tmp;
+	struct gfs2_buffer_head *bh;
+	uint64_t block, *ptr;
 	uint32_t height = ip->i_di.di_height;
+	int  i, head_size;
 	int update = 0;
 	int error = 0;
 
-	if (height) {
-		/* create metalist for each level */
-		if(build_and_check_metalist(ip, pass)){
-			stack;
-			return -1;
+	if (!height)
+		goto end;
+
+	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)){
+		stack;
+		return -1;
+	}
+
+	/* 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 %"PRIu64"\n",
+			  ip->i_di.di_num.no_addr);
+
+	/* check data blocks */
+	list = &metalist[height - 1];
+
+	for (tmp = list->next; tmp != list; tmp = tmp->next) {
+		bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_altlist);
+
+		head_size = (height != 1 ? sizeof(struct gfs2_meta_header) :
+			     sizeof(struct gfs2_dinode));
+		ptr = (uint64_t *)(bh->b_data + head_size);
+
+		for ( ; (char *)ptr < (bh->b_data + bh->b_size); ptr++)	{
+			if (!*ptr)
+				continue;
+
+			block =  be64_to_cpu(*ptr);
+
+			if(pass->check_data &&
+			   (pass->check_data(ip, block, pass->private) < 0)) {
+				stack;
+				return -1;
+			}
+		}
+	}
+
+	/* free metalists */
+	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
+	{
+		list = &metalist[i];
+		while (!osi_list_empty(list))
+		{
+			bh = osi_list_entry(list->next,
+					    struct gfs2_buffer_head, b_altlist);
+			osi_list_del(&bh->b_altlist);
 		}
 	}
-	if (S_ISDIR(ip->i_di.di_mode)) {
+
+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(ip, &update, pass);
--- cluster/gfs2/libgfs2/libgfs2.h	2007/07/10 18:21:35	1.7.2.9
+++ cluster/gfs2/libgfs2/libgfs2.h	2007/09/16 17:19:03	1.7.2.9.2.1
@@ -93,13 +93,13 @@
 struct gfs2_buffer_head {
 	osi_list_t b_list;
 	osi_list_t b_hash;
+	osi_list_t b_altlist; /* alternate list */
 
 	unsigned int b_count;
 	uint64_t b_blocknr;
 	char *b_data;
 	unsigned int b_size;
 
-	int b_uninit;
 	int b_changed;
 };
 
@@ -496,7 +496,13 @@
 void decrease_verbosity(void);
 void print_fsck_log(int iif, int priority, char *file, int line,
 					const char *format, ...);
-int query(struct gfs2_options *opts, const char *format, ...);
+char gfs2_getch(void);
+
+char generic_interrupt(const char *caller, const char *where,
+		       const char *progress, const char *question,
+		       const char *answers);
+int gfs2_query(int *setonabort, struct gfs2_options *opts,
+	       const char *format, ...);
 
 /* misc.c */
 void compute_constants(struct gfs2_sbd *sdp);
--- cluster/gfs2/libgfs2/structures.c	2007/06/26 01:51:44	1.5.2.5
+++ cluster/gfs2/libgfs2/structures.c	2007/09/16 17:19:03	1.5.2.5.2.1
@@ -56,7 +56,6 @@
 	for (x = 0; x < sdp->sb_addr; x++) {
 		bh = bget(sdp, x);
 		memset(bh->b_data, 0, sdp->bsize);
-		bh->b_uninit = TRUE;
 		brelse(bh, updated);
 	}
 




More information about the Cluster-devel mailing list