[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