CVSROOT:        /cvs/cluster
Module name:    cluster
Changes by:     [EMAIL PROTECTED]       2007-09-16 17:14:45

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&r1=1.10&r2=1.11
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/libgfs2.h.diff?cvsroot=cluster&r1=1.17&r2=1.18
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/structures.c.diff?cvsroot=cluster&r1=1.10&r2=1.11

--- cluster/gfs2/fsck/metawalk.c        2007/06/28 23:41:37     1.10
+++ cluster/gfs2/fsck/metawalk.c        2007/09/16 17:14:45     1.11
@@ -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/08/15 22:28:18     1.17
+++ cluster/gfs2/libgfs2/libgfs2.h      2007/09/16 17:14:45     1.18
@@ -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;
 };
 
--- cluster/gfs2/libgfs2/structures.c   2007/06/26 01:43:17     1.10
+++ cluster/gfs2/libgfs2/structures.c   2007/09/16 17:14:45     1.11
@@ -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);
        }
 

Reply via email to