Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9383e745e23602bc45f9c92184feea59 > files > 37

gfs2-utils-0.1.62-28.el5.src.rpm

commit d5225059548822d41cc15fa8c754e2ec9a4d2c90
Author: Bob Peterson <bob@ganesha.peterson>
Date:   Fri Jan 22 14:38:05 2010 -0600

    fsck.gfs2: separate check_data function in check_metatree
    
    Function check_metatree had a loop for checking data blocks.  I broke
    this loop into its own function.  That serves two purposes: First, it
    makes check_metatree smaller and easier to read (it's already big an
    unruly).  Second, it avoids looping unnecessarily when the caller
    has no check_data() function of its own.  Net result is faster code.
    
    rhbz#455300

diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index de7beac..f9fd733 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1169,6 +1169,49 @@ fail:
 }
 
 /**
+ * check_data - check all data pointers for a given buffer
+ *              This does not include "data" blocks that are really
+ *              hash table blocks for directories.
+ *
+ * @ip: 
+ * 
+ * returns: +ENOENT if there are too many bad pointers
+ *          -1 if a more serious error occurred.
+ *          0 if no errors occurred
+ *          1 if errors were found and corrected
+ *          2 (ENOENT) is there were too many bad pointers
+ */
+static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
+		      uint64_t *ptr_start, char *ptr_end,
+		      uint64_t *blks_checked)
+{
+	int error = 0, rc = 0;
+	uint64_t block, *ptr;
+
+	/* If there isn't much pointer corruption check the pointers */
+	for (ptr = ptr_start ; (char *)ptr < ptr_end && !fsck_abort; ptr++) {
+		if (!*ptr)
+			continue;
+
+		if (skip_this_pass || fsck_abort)
+			return error;
+		block =  be64_to_cpu(*ptr);
+		/* It's important that we don't call gfs2_check_range and
+		   bypass calling check_data on invalid blocks because that
+		   would defeat the rangecheck_block related functions in
+		   pass1. Therefore the individual check_data functions
+		   should do a range check. */
+		rc = pass->check_data(ip, block, pass->private);
+		if (rc < 0)
+			return rc;
+		if (!error && rc)
+			error = rc;
+		(*blks_checked)++;
+	}
+	return error;
+}
+
+/**
  * check_metatree
  * @ip:
  * @rgd:
@@ -1179,11 +1222,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
 	osi_list_t *list;
 	struct gfs2_buffer_head *bh;
-	uint64_t block, *ptr;
 	uint32_t height = ip->i_di.di_height;
 	int  i, head_size;
 	uint64_t blks_checked = 0;
-	int error;
+	int error, rc;
 
 	if (!height && !S_ISDIR(ip->i_di.di_mode))
 		return 0;
@@ -1239,23 +1281,19 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 			}
 			head_size = sizeof(struct gfs2_dinode);
 		}
-		ptr = (uint64_t *)(bh->b_data + head_size);
 
-		for ( ; (char *)ptr < (bh->b_data + ip->i_sbd->bsize); ptr++) {
-			if (!*ptr)
-				continue;
-
-			block =  be64_to_cpu(*ptr);
+		if (pass->check_data)
+			rc = check_data(ip, pass, (uint64_t *)
+					(bh->b_data + head_size),
+					(bh->b_data + ip->i_sbd->bsize),
+					&blks_checked);
+		else
+			rc = 0;
 
-			if(pass->check_data &&
-			   (pass->check_data(ip, block, pass->private) < 0)) {
-				stack;
-				return -1;
-			}
-			blks_checked++;
-			if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
-				big_file_comfort(ip, blks_checked);
-		}
+		if (rc && (!error || rc < 0))
+			error = rc;
+		if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
+			big_file_comfort(ip, blks_checked);
 		if (bh == ip->i_bh)
 			osi_list_del(&bh->b_altlist);
 		else