Gitweb:
http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 5df69b1d9f020df9e97629240196596c330567fa
Parent: 611c213c35e1af8dc36f3b15fccc5ee5c352eaa3
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 14:38:05 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 14:39:31 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
---
gfs2/fsck/metawalk.c | 72 ++++++++++++++++++++++++++++++++++++++------------
1 files changed, 55 insertions(+), 17 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 13290e1..2ad47fe 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1157,6 +1157,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:
@@ -1167,11 +1210,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;
@@ -1227,23 +1269,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