LCOV - code coverage report
Current view: top level - fsck - pass1.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 295 880 33.5 %
Date: 2023-09-27 13:48:55 Functions: 27 56 48.2 %

          Line data    Source code
       1             : /* pass1 checks inodes for format & type, duplicate blocks, & incorrect
       2             :  * block count.
       3             :  *
       4             :  * It builds up tables that contains the state of each block (free,
       5             :  * block in use, metadata type, etc), as well as bad blocks and
       6             :  * duplicate blocks.  (See block_list.[ch] for more info)
       7             :  *
       8             :  */
       9             : 
      10             : #include <stdio.h>
      11             : #include <stdlib.h>
      12             : #include <sys/time.h>
      13             : #include <sys/stat.h>
      14             : #include <unistd.h>
      15             : #include <string.h>
      16             : #include <time.h>
      17             : #include <fcntl.h>
      18             : #include <sys/ioctl.h>
      19             : #include <inttypes.h>
      20             : #include <libintl.h>
      21             : #define _(String) gettext(String)
      22             : 
      23             : #include <logging.h>
      24             : #include "libgfs2.h"
      25             : #include "fsck.h"
      26             : #include "inode_hash.h"
      27             : #include "util.h"
      28             : #include "link.h"
      29             : #include "metawalk.h"
      30             : #include "fs_recovery.h"
      31             : 
      32             : static struct bmap *bl = NULL;
      33             : static struct metawalk_fxns pass1_fxns;
      34             : 
      35             : struct block_count {
      36             :         uint64_t indir_count;
      37             :         uint64_t data_count;
      38             :         uint64_t ea_count;
      39             : };
      40             : 
      41     2115168 : static int blockmap_set(struct bmap *bmap, uint64_t bblock, int mark)
      42             : {
      43             :         static unsigned char *byte;
      44             :         static uint64_t b;
      45             : 
      46     2115168 :         if (!bmap)
      47           0 :                 return 0;
      48     2115168 :         if (bblock > bmap->size)
      49           0 :                 return -1;
      50             : 
      51     2115168 :         byte = bmap->map + BLOCKMAP_SIZE2(bblock);
      52     2115168 :         b = BLOCKMAP_BYTE_OFFSET2(bblock);
      53     2115168 :         *byte &= ~(BLOCKMAP_MASK2 << b);
      54     2115168 :         *byte |= (mark & BLOCKMAP_MASK2) << b;
      55     2115168 :         return 0;
      56             : }
      57             : 
      58             : /*
      59             :  * _fsck_blockmap_set - Mark a block in the 4-bit blockmap and the 2-bit
      60             :  *                      bitmap, and adjust free space accordingly.
      61             :  */
      62     1982705 : static int _fsck_blockmap_set(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t bblock,
      63             :                               const char *btype, int mark, int error_on_dinode,
      64             :                               const char *caller, int fline)
      65             : {
      66     1982705 :         int error = _fsck_bitmap_set(cx, ip, bblock, btype, mark, error_on_dinode,
      67             :                                      caller, fline);
      68     1982705 :         if (error)
      69           0 :                 return error;
      70             : 
      71     1982705 :         return blockmap_set(bl, bblock, mark);
      72             : }
      73             : 
      74             : #define fsck_blockmap_set(cx, ip, b, bt, m) \
      75             :         _fsck_blockmap_set(cx, ip, b, bt, m, 0, __FUNCTION__, __LINE__)
      76             : #define fsck_blkmap_set_noino(cx, ip, b, bt, m) \
      77             :         _fsck_blockmap_set(cx, ip, b, bt, m, 1, __FUNCTION__, __LINE__)
      78             : 
      79             : /**
      80             :  * p1_delete_block - delete a block associated with an inode
      81             :  */
      82           0 : static int p1_delete_block(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
      83             :                         struct lgfs2_buffer_head **bh, const char *btype,
      84             :                         void *private)
      85             : {
      86           0 :         if (valid_block_ip(ip, block)) {
      87           0 :                 fsck_blockmap_set(cx, ip, block, btype, GFS2_BLKST_FREE);
      88           0 :                 return 0;
      89             :         }
      90           0 :         return -1;
      91             : }
      92             : 
      93             : /* This is a pass1-specific leaf repair. Since we are not allowed to do
      94             :  * block allocations, we do what we can. */
      95           0 : static int p1_repair_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t *leaf_no,
      96             :                              int lindex, int ref_count, const char *msg)
      97             : {
      98             :         uint64_t *cpyptr;
      99             :         char *padbuf;
     100             :         int pad_size, i;
     101             : 
     102           0 :         log_err(_("Directory Inode %"PRIu64" (0x%"PRIx64") points to leaf %"PRIu64" (0x%"PRIx64") %s.\n"),
     103             :                ip->i_num.in_addr, ip->i_num.in_addr, *leaf_no, *leaf_no, msg);
     104           0 :         if (!query(cx, _("Attempt to patch around it? (y/n) "))) {
     105           0 :                 log_err( _("Bad leaf left in place.\n"));
     106           0 :                 goto out;
     107             :         }
     108             : 
     109           0 :         padbuf = malloc(ref_count * sizeof(uint64_t));
     110           0 :         cpyptr = (uint64_t *)padbuf;
     111           0 :         for (i = 0; i < ref_count; i++) {
     112           0 :                 *cpyptr = 0;
     113           0 :                 cpyptr++;
     114             :         }
     115           0 :         pad_size = ref_count * sizeof(uint64_t);
     116           0 :         log_err(_("Writing zeros to the hash table of directory %"PRIu64
     117             :                   " (0x%"PRIx64") at index: 0x%x for 0x%x pointers.\n"),
     118             :                 ip->i_num.in_addr, ip->i_num.in_addr, lindex, ref_count);
     119           0 :         lgfs2_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
     120           0 :         free(padbuf);
     121           0 :         log_err(_("Directory Inode %"PRIu64" (0x%"PRIx64") patched.\n"),
     122             :                 ip->i_num.in_addr, ip->i_num.in_addr);
     123             : 
     124           0 : out:
     125           0 :         *leaf_no = 0;
     126           0 :         return 0;
     127             : }
     128             : 
     129             : /*
     130             :  * resuscitate_metalist - make sure a system directory entry's metadata blocks
     131             :  *                        are marked "in use" in the bitmap.
     132             :  *
     133             :  * This function makes sure metadata blocks for system and root directories are
     134             :  * marked "in use" by the bitmap.  You don't want root's indirect blocks
     135             :  * deleted, do you? Or worse, reused for lost+found.
     136             :  */
     137           0 : static int resuscitate_metalist(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
     138             :                                 int *is_valid, int *was_duplicate, void *private)
     139             : {
     140           0 :         struct block_count *bc = (struct block_count *)private;
     141           0 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     142           0 :         uint64_t block = iptr_block(iptr);
     143             : 
     144           0 :         *is_valid = 1;
     145           0 :         *was_duplicate = 0;
     146           0 :         *bh = NULL;
     147           0 :         if (!valid_block_ip(ip, block)){ /* blk outside of FS */
     148           0 :                 fsck_blockmap_set(cx, ip, ip->i_num.in_addr, _("itself"), GFS2_BLKST_UNLINKED);
     149           0 :                 log_err(_("Bad indirect block pointer (invalid or out of "
     150             :                           "range) found in system inode %"PRIu64" (0x%"PRIx64").\n"),
     151             :                         ip->i_num.in_addr, ip->i_num.in_addr);
     152           0 :                 *is_valid = 0;
     153           0 :                 return META_IS_GOOD;
     154             :         }
     155           0 :         if (fsck_system_inode(ip->i_sbd, block))
     156           0 :                 fsck_blockmap_set(cx, ip, block, _("system file"), GFS2_BLKST_USED);
     157             :         else
     158           0 :                 check_n_fix_bitmap(cx, ip->i_rgd, block, 0, GFS2_BLKST_USED);
     159           0 :         bc->indir_count++;
     160           0 :         return META_IS_GOOD;
     161             : }
     162             : 
     163             : /*
     164             :  * resuscitate_dentry - make sure a system directory entry is alive
     165             :  *
     166             :  * This function makes sure directory entries in system directories are
     167             :  * kept alive.  You don't want journal0 deleted from jindex, do you?
     168             :  */
     169        1036 : static int resuscitate_dentry(struct fsck_cx *cx, struct lgfs2_inode *ip, struct gfs2_dirent *dent,
     170             :                               struct gfs2_dirent *prev_de,
     171             :                               struct lgfs2_buffer_head *bh, char *filename,
     172             :                               uint32_t *count, int *lindex, void *priv)
     173             : {
     174        1036 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     175             :         struct lgfs2_dirent d;
     176             :         char tmp_name[GFS2_FNAMESIZE];
     177             :         uint64_t block;
     178             : 
     179        1036 :         lgfs2_dirent_in(&d, dent);
     180        1036 :         block = d.dr_inum.in_addr;
     181             :         /* Start of checks */
     182        1036 :         memset(tmp_name, 0, sizeof(tmp_name));
     183        1036 :         if (d.dr_name_len < sizeof(tmp_name))
     184        1036 :                 strncpy(tmp_name, filename, d.dr_name_len);
     185             :         else
     186           0 :                 strncpy(tmp_name, filename, sizeof(tmp_name) - 1);
     187        1036 :         if (!valid_block_ip(ip, block)) {
     188           0 :                 log_err(_("Block # referenced by system directory entry %s in inode "
     189             :                           "%"PRIu64" (0x%"PRIx64") is invalid or out of range; ignored.\n"),
     190             :                         tmp_name, ip->i_num.in_addr, ip->i_num.in_addr);
     191           0 :                 return 0;
     192             :         }
     193             :         /* If this is a system dinode, we'll handle it later in
     194             :            check_system_inodes.  If not, it'll be handled by pass1 but
     195             :            since it's in a system directory we need to make sure it's
     196             :            represented in the rgrp bitmap. */
     197        1036 :         if (fsck_system_inode(sdp, block))
     198         846 :                 fsck_blockmap_set(cx, ip, block, _("system file"),
     199             :                                   GFS2_BLKST_DINODE);
     200             :         else
     201         190 :                 check_n_fix_bitmap(cx, ip->i_rgd, block, 0,
     202             :                                    GFS2_BLKST_DINODE);
     203             :         /* Return the number of leaf entries so metawalk doesn't flag this
     204             :            leaf as having none. */
     205        1036 :         *count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
     206        1036 :         return 0;
     207             : }
     208             : 
     209             : static struct metawalk_fxns sysdir_fxns = {
     210             :         .private = NULL,
     211             :         .check_metalist = resuscitate_metalist,
     212             :         .check_dentry = resuscitate_dentry,
     213             :         .delete_block = p1_delete_block,
     214             : };
     215             : 
     216           9 : static int p1_check_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, void *private)
     217             : {
     218           9 :         struct block_count *bc = (struct block_count *) private;
     219             :         int q;
     220             : 
     221             :         /* Note if we've gotten this far, the block has already passed the
     222             :            check in metawalk: lgfs2_check_meta(lbh, GFS2_METATYPE_LF).
     223             :            So we know it's a leaf block. */
     224           9 :         bc->indir_count++;
     225           9 :         q = block_type(bl, block);
     226           9 :         if (q != GFS2_BLKST_FREE) {
     227           0 :                 log_err(_("Found duplicate block #%"PRIu64" (0x%"PRIx64") referenced "
     228             :                           "as a directory leaf in dinode "
     229             :                           "%"PRIu64" (0x%"PRIx64") - was marked %d (%s)\n"),
     230             :                         block, block, ip->i_num.in_addr, ip->i_num.in_addr, q,
     231             :                         block_type_string(q));
     232           0 :                 add_duplicate_ref(cx, ip, block, REF_AS_META, 0, INODE_VALID);
     233           0 :                 if (q == GFS2_BLKST_USED)
     234             :                         /* If the previous reference also saw this as a leaf,
     235             :                            it was already checked, so don't check again. */
     236           0 :                         return EEXIST; /* non-fatal */
     237             :         }
     238           9 :         fsck_blockmap_set(cx, ip, block, _("directory leaf"), GFS2_BLKST_USED);
     239           9 :         return 0;
     240             : }
     241             : 
     242        7361 : static int p1_check_metalist(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
     243             :                                 int *is_valid, int *was_duplicate, void *private)
     244             : {
     245        7361 :         struct block_count *bc = (struct block_count *)private;
     246        7361 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     247        7361 :         uint64_t block = iptr_block(iptr);
     248             :         struct lgfs2_buffer_head *nbh;
     249             :         const char *blktypedesc;
     250             :         int iblk_type;
     251             :         int q;
     252             : 
     253        7361 :         *bh = NULL;
     254             : 
     255        7361 :         *was_duplicate = 0;
     256        7361 :         *is_valid = 0;
     257        7361 :         if (!valid_block_ip(ip, block)) { /* blk outside of FS */
     258             :                 /* The bad dinode should be invalidated later due to
     259             :                    "unrecoverable" errors.  The inode itself should be
     260             :                    set "free" and removed from the inodetree by
     261             :                    undo_check_metalist. */
     262           0 :                 fsck_blockmap_set(cx, ip, ip->i_num.in_addr,
     263             :                                   _("bad block referencing"), GFS2_BLKST_UNLINKED);
     264           0 :                 log_debug(_("Bad indirect block (invalid/out of range) "
     265             :                             "found in inode %"PRIu64" (0x%"PRIx64").\n"),
     266             :                           ip->i_num.in_addr, ip->i_num.in_addr);
     267             : 
     268           0 :                 return META_SKIP_FURTHER;
     269             :         }
     270        7361 :         if (is_dir(ip) && h == ip->i_height) {
     271           0 :                 iblk_type = GFS2_METATYPE_JD;
     272           0 :                 blktypedesc = _("a directory hash table block");
     273             :         } else {
     274        7361 :                 iblk_type = GFS2_METATYPE_IN;
     275        7361 :                 blktypedesc = _("a journaled data block");
     276             :         }
     277        7361 :         q = block_type(bl, block);
     278        7361 :         if (q != GFS2_BLKST_FREE) {
     279           0 :                 log_err(_("Found duplicate block #%"PRIu64" (0x%"PRIx64") referenced "
     280             :                           "as metadata in indirect block for dinode "
     281             :                           "%"PRIu64" (0x%"PRIx64") - was marked %d (%s)\n"),
     282             :                          block, block, ip->i_num.in_addr, ip->i_num.in_addr, q,
     283             :                          block_type_string(q));
     284           0 :                 *was_duplicate = 1;
     285             :         }
     286        7361 :         nbh = lgfs2_bread(ip->i_sbd, block);
     287             : 
     288        7361 :         *is_valid = (lgfs2_check_meta(nbh->b_data, iblk_type) == 0);
     289             : 
     290        7361 :         if (!(*is_valid)) {
     291           0 :                 log_err(_("Inode %"PRIu64" (0x%"PRIx64") has a bad indirect block "
     292             :                           "pointer %"PRIu64" (0x%"PRIx64") (points to something "
     293             :                           "that is not %s).\n"),
     294             :                          ip->i_num.in_addr, ip->i_num.in_addr, block, block, blktypedesc);
     295           0 :                 if (query(cx, _("Zero the indirect block pointer? (y/n) "))){
     296           0 :                         *iptr_ptr(iptr) = 0;
     297           0 :                         lgfs2_bmodified(iptr.ipt_bh);
     298           0 :                         *is_valid = 1;
     299           0 :                         lgfs2_brelse(nbh);
     300           0 :                         return META_SKIP_ONE;
     301             :                 } else {
     302           0 :                         lgfs2_brelse(nbh);
     303           0 :                         return META_SKIP_FURTHER;
     304             :                 }
     305             :         }
     306             : 
     307        7361 :         bc->indir_count++;
     308        7361 :         if (*was_duplicate) {
     309           0 :                 add_duplicate_ref(cx, ip, block, REF_AS_META, 0,
     310           0 :                                   *is_valid ? INODE_VALID : INODE_INVALID);
     311           0 :                 lgfs2_brelse(nbh);
     312             :         } else {
     313        7361 :                 *bh = nbh;
     314        7361 :                 fsck_blockmap_set(cx, ip, block, _("indirect"), GFS2_BLKST_USED);
     315             :         }
     316             : 
     317        7361 :         if (*is_valid)
     318        7361 :                 return META_IS_GOOD;
     319           0 :         return META_SKIP_FURTHER;
     320             : }
     321             : 
     322             : /* undo_reference - undo previously processed data or metadata
     323             :  * We've treated the metadata for this dinode as good so far, but not we
     324             :  * realize it's bad. So we need to undo what we've done.
     325             :  *
     326             :  * Returns: 0 - We need to process the block as metadata. In other words,
     327             :  *              we need to undo any blocks it refers to.
     328             :  *          1 - We can't process the block as metadata.
     329             :  */
     330             : 
     331           0 : static int undo_reference(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, int meta,
     332             :                           void *private)
     333             : {
     334           0 :         struct block_count *bc = (struct block_count *)private;
     335             :         struct duptree *dt;
     336             :         struct inode_with_dups *id;
     337           0 :         int old_bitmap_state = 0;
     338             :         struct lgfs2_rgrp_tree *rgd;
     339             : 
     340           0 :         if (!valid_block_ip(ip, block)) { /* blk outside of FS */
     341           0 :                 fsck_blockmap_set(cx, ip, ip->i_num.in_addr, _("bad block referencing"), GFS2_BLKST_FREE);
     342           0 :                 return 1;
     343             :         }
     344             : 
     345           0 :         if (meta)
     346           0 :                 bc->indir_count--;
     347           0 :         dt = dupfind(cx, block);
     348           0 :         if (dt) {
     349             :                 /* remove all duplicate reference structures from this inode */
     350             :                 do {
     351           0 :                         id = find_dup_ref_inode(dt, ip);
     352           0 :                         if (!id)
     353           0 :                                 break;
     354             : 
     355           0 :                         dup_listent_delete(dt, id);
     356           0 :                 } while (id);
     357             : 
     358           0 :                 if (dt->refs) {
     359           0 :                         log_err(_("Block %"PRIu64" (0x%"PRIx64") is still referenced "
     360             :                                   "from another inode; not freeing.\n"),
     361             :                                 block, block);
     362           0 :                         if (dt->refs == 1) {
     363           0 :                                 log_err(_("This was the only duplicate "
     364             :                                           "reference so far; removing it.\n"));
     365           0 :                                 dup_delete(cx, dt);
     366             :                         }
     367           0 :                         return 1;
     368             :                 }
     369             :         }
     370           0 :         if (!meta) {
     371           0 :                 rgd = lgfs2_blk2rgrpd(ip->i_sbd, block);
     372           0 :                 old_bitmap_state = lgfs2_get_bitmap(ip->i_sbd, block, rgd);
     373           0 :                 if (old_bitmap_state == GFS2_BLKST_DINODE)
     374           0 :                         return -1;
     375             :         }
     376           0 :         fsck_blockmap_set(cx, ip, block,
     377             :                           meta ? _("bad indirect") : _("referenced data"),
     378             :                           GFS2_BLKST_FREE);
     379           0 :         return 0;
     380             : }
     381             : 
     382           0 : static int p1_undo_check_metalist(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     383             :                                int h, void *private)
     384             : {
     385           0 :         return undo_reference(cx, ip, block, 1, private);
     386             : }
     387             : 
     388           0 : static int p1_undo_check_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     389             :                            void *private)
     390             : {
     391           0 :         return undo_reference(cx, ip, block, 0, private);
     392             : }
     393             : 
     394             : /* blockmap_set_as_data - set block as 'data' in the blockmap, if not dinode
     395             :  *
     396             :  * This function tries to set a block that's referenced as data as 'data'
     397             :  * in the fsck blockmap. But if that block is marked as 'dinode' in the
     398             :  * rgrp bitmap, it does additional checks to see if it looks like a dinode.
     399             :  * Note that previous checks were done for duplicate references, so this
     400             :  * is checking for dinodes that we haven't processed yet.
     401             :  */
     402     1973676 : static int blockmap_set_as_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block)
     403             : {
     404             :         int error;
     405             :         struct lgfs2_buffer_head *bh;
     406             :         struct gfs2_dinode *di;
     407             : 
     408     1973676 :         error = fsck_blkmap_set_noino(cx, ip, block, "data", GFS2_BLKST_USED);
     409     1973676 :         if (!error)
     410     1973676 :                 return 0;
     411             : 
     412           0 :         error = 0;
     413             :         /* The bitmap says it's a dinode, but a block reference begs to differ.
     414             :            So which is it? */
     415           0 :         bh = lgfs2_bread(ip->i_sbd, block);
     416           0 :         if (lgfs2_check_meta(bh->b_data, GFS2_METATYPE_DI) != 0)
     417           0 :                 goto out;
     418             : 
     419             :         /* The meta header agrees it's a dinode. But it might be data in
     420             :            disguise, so do some extra checks. */
     421           0 :         di = (struct gfs2_dinode *)bh->b_data;
     422           0 :         if (be64_to_cpu(di->di_num.no_addr) != block)
     423           0 :                 goto out;
     424             : 
     425           0 :         log_err(_("Inode %"PRIu64" (0x%"PRIx64") has a reference to block %"PRIu64" (0x%"PRIx64") "
     426             :                   "as a data block, but it appears to be a dinode we haven't checked yet.\n"),
     427             :                 ip->i_num.in_addr, ip->i_num.in_addr, block, block);
     428           0 :         error = -1;
     429           0 : out:
     430           0 :         if (!error)
     431           0 :                 fsck_blockmap_set(cx, ip, block, "data",  GFS2_BLKST_USED);
     432           0 :         lgfs2_brelse(bh);
     433           0 :         return error;
     434             : }
     435             : 
     436     1973676 : static int p1_check_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
     437             :                       uint64_t block, void *private,
     438             :                       struct lgfs2_buffer_head *bbh, __be64 *ptr)
     439             : {
     440             :         int q;
     441     1973676 :         struct block_count *bc = (struct block_count *) private;
     442             : 
     443     1973676 :         if (!valid_block_ip(ip, block)) {
     444           0 :                 log_err(_("inode %"PRIu64" (0x%"PRIx64") has a bad data block pointer "
     445             :                           "%"PRIu64" (0x%"PRIx64") (invalid or out of range) "),
     446             :                         ip->i_num.in_addr, ip->i_num.in_addr, block, block);
     447           0 :                 if (metablock == ip->i_num.in_addr)
     448           0 :                         log_err("\n");
     449             :                 else
     450           0 :                         log_err(_("from metadata block %"PRIu64" (0x%"PRIx64")\n"),
     451             :                                 metablock, metablock);
     452             :                 /* Mark the owner of this block with the bad_block
     453             :                  * designator so we know to check it for out of range
     454             :                  * blocks later */
     455           0 :                 fsck_blockmap_set(cx, ip, ip->i_num.in_addr, _("bad (out of range) data"), GFS2_BLKST_UNLINKED);
     456           0 :                 return -1;
     457             :         }
     458     1973676 :         bc->data_count++; /* keep the count sane anyway */
     459     1973676 :         q = block_type(bl, block);
     460     1973676 :         if (q != GFS2_BLKST_FREE) {
     461             :                 struct lgfs2_buffer_head *bh;
     462             :                 struct gfs2_meta_header *mh;
     463             :                 uint32_t mh_type;
     464             : 
     465           0 :                 log_err(_("Found duplicate %s block %"PRIu64" (0x%"PRIx64") "
     466             :                           "referenced as data by dinode %"PRIu64" (0x%"PRIx64") "),
     467             :                         block_type_string(q),
     468             :                         block, block, ip->i_num.in_addr, ip->i_num.in_addr);
     469           0 :                 if (metablock == ip->i_num.in_addr)
     470           0 :                         log_err("\n");
     471             :                 else
     472           0 :                         log_err(_("from metadata block %"PRIu64" (0x%"PRIx64")\n"),
     473             :                                 metablock, metablock);
     474             : 
     475           0 :                 switch (q) {
     476           0 :                 case GFS2_BLKST_DINODE:
     477           0 :                         log_info(_("The block was processed earlier as an "
     478             :                                    "inode, so it can't possibly be data.\n"));
     479             :                         /* We still need to add a duplicate record here because
     480             :                            when check_metatree tries to delete the inode, we
     481             :                            can't have the "undo" functions freeing the block
     482             :                            out from other the original referencing inode. */
     483           0 :                         add_duplicate_ref(cx, ip, block, REF_AS_DATA, 0,
     484             :                                           INODE_VALID);
     485           0 :                         return 1;
     486           0 :                 case GFS2_BLKST_USED: /* tough decision: May be data or meta */
     487           0 :                         bh = lgfs2_bread(ip->i_sbd, block);
     488           0 :                         mh = (struct gfs2_meta_header *)bh->b_data;
     489           0 :                         mh_type = be32_to_cpu(mh->mh_type);
     490           0 :                         lgfs2_brelse(bh);
     491           0 :                         if (be32_to_cpu(mh->mh_magic) == GFS2_MAGIC &&
     492           0 :                             mh_type >= GFS2_METATYPE_RG &&
     493           0 :                             mh_type <= GFS2_METATYPE_QC &&
     494           0 :                             mh_type != GFS2_METATYPE_DI &&
     495           0 :                             be32_to_cpu(mh->mh_format) % 100 == 0) {
     496           0 :                                 log_info(_("The block was processed earlier "
     497             :                                            "as valid metadata, so it can't "
     498             :                                            "possibly be data.\n"));
     499             :                                 /* We still need to add a duplicate record here
     500             :                                    because when check_metatree tries to delete
     501             :                                    the inode, we can't have the "undo"
     502             :                                    functions freeing the block out from other
     503             :                                    the original referencing inode. */
     504           0 :                                 add_duplicate_ref(cx, ip, block, REF_AS_DATA, 0,
     505             :                                                   INODE_VALID);
     506           0 :                                 return 1;
     507             :                         }
     508           0 :                         log_info( _("Seems to be a normal duplicate; I'll "
     509             :                                     "sort it out in pass1b.\n"));
     510           0 :                         add_duplicate_ref(cx, ip, block, REF_AS_DATA, 0,
     511             :                                           INODE_VALID);
     512             :                         /* This inode references the block as data. So if this
     513             :                            all is validated, we want to keep this count. */
     514           0 :                         return 0;
     515           0 :                 case GFS2_BLKST_UNLINKED:
     516           0 :                         log_info( _("The block was invalid as metadata but might be "
     517             :                                     "okay as data.  I'll sort it out in pass1b.\n"));
     518           0 :                         add_duplicate_ref(cx, ip, block, REF_AS_DATA, 0, INODE_VALID);
     519           0 :                         return 0;
     520             :                 }
     521             :         }
     522     1973676 :         return blockmap_set_as_data(cx, ip, block);
     523             : }
     524             : 
     525           0 : static int ask_remove_inode_eattr(struct fsck_cx *cx, struct lgfs2_inode *ip,
     526             :                                   struct block_count *bc)
     527             : {
     528           0 :         if (ip->i_eattr == 0)
     529           0 :                 return 0; /* eattr was removed prior to this call */
     530           0 :         log_err(_("Inode %"PRIu64" (0x%"PRIx64") has unrecoverable Extended Attribute errors.\n"),
     531             :                 ip->i_num.in_addr, ip->i_num.in_addr);
     532           0 :         if (query(cx, _("Clear all Extended Attributes from the inode? (y/n) "))){
     533           0 :                 undo_reference(cx, ip, ip->i_eattr, 0, bc);
     534           0 :                 ip->i_eattr = 0;
     535           0 :                 bc->ea_count = 0;
     536           0 :                 ip->i_blocks = 1 + bc->indir_count + bc->data_count;
     537           0 :                 ip->i_flags &= ~GFS2_DIF_EA_INDIRECT;
     538           0 :                 lgfs2_bmodified(ip->i_bh);
     539           0 :                 log_err( _("Extended attributes were removed.\n"));
     540             :         } else {
     541           0 :                 log_err( _("Extended attributes were not removed.\n"));
     542             :         }
     543           0 :         return 0;
     544             : }
     545             : 
     546           0 : static int undo_eattr_indir_or_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     547             :                                     uint64_t parent,
     548             :                                     struct lgfs2_buffer_head **bh,
     549             :                                     void *private)
     550             : {
     551           0 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     552             :         int q;
     553             :         int error;
     554           0 :         struct block_count *bc = (struct block_count *) private;
     555             : 
     556           0 :         if (!valid_block_ip(ip, block))
     557           0 :                 return META_ERROR;
     558             : 
     559             :         /* Need to check block_type before undoing the reference, which can
     560             :            set it to free, which would cause the test below to fail. */
     561           0 :         q = block_type(bl, block);
     562             : 
     563           0 :         error = undo_reference(cx, ip, block, 0, private);
     564           0 :         if (error)
     565           0 :                 return error;
     566             : 
     567           0 :         bc->ea_count--;
     568             : 
     569           0 :         if (q != GFS2_BLKST_USED)
     570           0 :                 return 1;
     571             : 
     572           0 :         *bh = lgfs2_bread(sdp, block);
     573           0 :         return 0;
     574             : }
     575             : 
     576             : /* complain_eas - complain about extended attribute errors for an inode
     577             :  *
     578             :  * @ip       - in core inode pointer
     579             :  * block     - the block that had the problem
     580             :  * duplicate - if this is a duplicate block, don't set it "free"
     581             :  * emsg      - what to tell the user about the eas being checked
     582             :  * Returns: 1 if the EA is fixed, else 0 if it was not fixed.
     583             :  */
     584           0 : static void complain_eas(struct lgfs2_inode *ip, uint64_t block,
     585             :                          const char *emsg)
     586             : {
     587           0 :         log_err(_("Inode #%"PRIu64" (0x%"PRIx64"): %s"), ip->i_num.in_addr, ip->i_num.in_addr, emsg);
     588           0 :         log_err(_(" at block #%"PRIu64" (0x%"PRIx64").\n"), block, block);
     589           0 : }
     590             : 
     591           0 : static int p1_check_eattr_indir(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t indirect,
     592             :                              uint64_t parent, struct lgfs2_buffer_head **bh,
     593             :                              void *private)
     594             : {
     595           0 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     596           0 :         int ret = 0;
     597             :         int q;
     598           0 :         struct block_count *bc = (struct block_count *) private;
     599             : 
     600             :         /* This inode contains an eattr - it may be invalid, but the
     601             :          * eattr attributes points to a non-zero block */
     602           0 :         if (!valid_block_ip(ip, indirect)) {
     603             :                 /* Doesn't help to mark this here - this gets checked
     604             :                  * in pass1c */
     605           0 :                 return 1;
     606             :         }
     607           0 :         q = block_type(bl, indirect);
     608             : 
     609             :         /* Special duplicate processing:  If we have an EA block,
     610             :            check if it really is an EA.  If it is, let duplicate
     611             :            handling sort it out.  If it isn't, clear it but don't
     612             :            count it as a duplicate. */
     613           0 :         *bh = lgfs2_bread(sdp, indirect);
     614           0 :         if (lgfs2_check_meta((*bh)->b_data, GFS2_METATYPE_IN)) {
     615           0 :                 bc->ea_count++;
     616           0 :                 if (q != GFS2_BLKST_FREE) { /* Duplicate? */
     617           0 :                         add_duplicate_ref(cx, ip, indirect, REF_AS_EA, 0,
     618             :                                           INODE_VALID);
     619           0 :                         complain_eas(ip, indirect,
     620           0 :                                      _("Bad indirect Extended Attribute "
     621             :                                        "duplicate found"));
     622             :                         /* Return 0 here because if all that's wrong is a
     623             :                            duplicate block reference, we want pass1b to figure
     624             :                            it out. We don't want to delete all the extended
     625             :                            attributes as if they are in error. */
     626           0 :                         return 0;
     627             :                 }
     628           0 :                 complain_eas(ip, indirect,
     629           0 :                              _("Extended Attribute indirect block has "
     630             :                                "incorrect type"));
     631           0 :                 return 1;
     632             :         }
     633           0 :         if (q != GFS2_BLKST_FREE) { /* Duplicate? */
     634           0 :                 add_duplicate_ref(cx, ip, indirect, REF_AS_EA, 0, INODE_VALID);
     635           0 :                 complain_eas(ip, indirect,
     636           0 :                              _("Duplicate Extended Attribute indirect block"));
     637           0 :                 bc->ea_count++;
     638           0 :                 ret = 0; /* For the same reason stated above. */
     639             :         } else {
     640           0 :                 fsck_blockmap_set(cx, ip, indirect,
     641             :                                   _("indirect Extended Attribute"), GFS2_BLKST_USED);
     642           0 :                 bc->ea_count++;
     643             :         }
     644           0 :         return ret;
     645             : }
     646             : 
     647           0 : static int p1_finish_eattr_indir(struct fsck_cx *cx, struct lgfs2_inode *ip, int leaf_pointers,
     648             :                               int leaf_pointer_errors, void *private)
     649             : {
     650           0 :         struct block_count *bc = (struct block_count *) private;
     651             : 
     652           0 :         if (leaf_pointer_errors == leaf_pointers) /* All eas were bad */
     653           0 :                 return ask_remove_inode_eattr(cx, ip, bc);
     654           0 :         log_debug(_("Marking inode #%"PRIu64" (0x%"PRIx64") with extended attribute block\n"),
     655             :                    ip->i_num.in_addr, ip->i_num.in_addr);
     656           0 :         if (!leaf_pointer_errors)
     657           0 :                 return 0;
     658           0 :         log_err(_("Inode %"PRIu64" (0x%"PRIx64") has recoverable indirect extended attribute errors.\n"),
     659             :                 ip->i_num.in_addr, ip->i_num.in_addr);
     660           0 :         if (query(cx, _("Okay to fix the block count for the inode? (y/n) "))) {
     661           0 :                 ip->i_blocks = 1 + bc->indir_count + bc->data_count + bc->ea_count;
     662           0 :                 lgfs2_bmodified(ip->i_bh);
     663           0 :                 log_err(_("Block count fixed: 1+%"PRIu64"+%"PRIu64"+%"PRIu64" = %"PRIu64".\n"),
     664             :                         bc->indir_count, bc->data_count, bc->ea_count, ip->i_blocks);
     665           0 :                 return 1;
     666             :         }
     667           0 :         log_err( _("Block count not fixed.\n"));
     668           0 :         return 1;
     669             : }
     670             : 
     671             : /* check_ealeaf_block
     672             :  *      checks an extended attribute (not directory) leaf block
     673             :  */
     674           0 : static int check_ealeaf_block(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, int btype,
     675             :                               struct lgfs2_buffer_head **bh, void *private)
     676             : {
     677           0 :         struct lgfs2_buffer_head *leaf_bh = NULL;
     678           0 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     679             :         int q;
     680           0 :         struct block_count *bc = (struct block_count *) private;
     681             : 
     682           0 :         q = block_type(bl, block);
     683             :         /* Special duplicate processing:  If we have an EA block, check if it
     684             :            really is an EA.  If it is, let duplicate handling sort it out.
     685             :            If it isn't, clear it but don't count it as a duplicate. */
     686           0 :         leaf_bh = lgfs2_bread(sdp, block);
     687           0 :         if (lgfs2_check_meta(leaf_bh->b_data, btype)) {
     688           0 :                 bc->ea_count++;
     689           0 :                 if (q != GFS2_BLKST_FREE) { /* Duplicate? */
     690           0 :                         add_duplicate_ref(cx, ip, block, REF_AS_EA, 0,
     691             :                                           INODE_VALID);
     692           0 :                         complain_eas(ip, block, _("Extended attribute leaf "
     693             :                                                   "duplicate found"));
     694           0 :                         lgfs2_bfree(&leaf_bh);
     695             :                         /* Return 0 here because if all that's wrong is a
     696             :                            duplicate block reference, we want pass1b to figure
     697             :                            it out. We don't want to delete all the extended
     698             :                            attributes as if they are in error. */
     699           0 :                         return 0;
     700             :                 }
     701           0 :                 complain_eas(ip, block, _("Extended Attribute leaf block has "
     702             :                                           "incorrect type"));
     703           0 :                 lgfs2_brelse(leaf_bh);
     704           0 :                 return 1;
     705             :         }
     706           0 :         if (q != GFS2_BLKST_FREE) { /* Duplicate? */
     707           0 :                 complain_eas(ip, block, _("Extended Attribute leaf "
     708             :                                           "duplicate found"));
     709           0 :                 add_duplicate_ref(cx, ip, block, REF_AS_DATA, 0, INODE_VALID);
     710           0 :                 bc->ea_count++;
     711           0 :                 lgfs2_brelse(leaf_bh);
     712             :                 /* Return 0 here because if all that's wrong is a duplicate
     713             :                    block reference, we want pass1b to figure it out. We don't
     714             :                    want to delete all the extended attributes as if they are
     715             :                    in error. */
     716           0 :                 return 0;
     717             :         }
     718             :         /* Point of confusion: We've got to set the ea block itself to
     719             :            GFS2_BLKST_USED here.  Elsewhere we mark the inode with
     720             :            gfs2_eattr_block meaning it contains an eattr. */
     721           0 :         fsck_blockmap_set(cx, ip, block, _("Extended Attribute"), GFS2_BLKST_USED);
     722           0 :         bc->ea_count++;
     723           0 :         *bh = leaf_bh;
     724           0 :         return 0;
     725             : }
     726             : 
     727             : /**
     728             :  * p1_check_extended_leaf_eattr
     729             :  * @ip
     730             :  * @el_blk: block number of the extended leaf
     731             :  *
     732             :  * An EA leaf block can contain EA's with pointers to blocks
     733             :  * where the data for that EA is kept.  Those blocks still
     734             :  * have the gfs2 meta header of type GFS2_METATYPE_EA
     735             :  *
     736             :  * Returns: 0 if correct[able], -1 if removal is needed
     737             :  */
     738           0 : static int p1_check_extended_leaf_eattr(struct fsck_cx *cx, struct lgfs2_inode *ip, int i,
     739             :                                      __be64 *data_ptr,
     740             :                                      struct lgfs2_buffer_head *leaf_bh,
     741             :                                      uint32_t tot_ealen,
     742             :                                      struct gfs2_ea_header *ea_hdr,
     743             :                                      struct gfs2_ea_header *ea_hdr_prev,
     744             :                                      void *private)
     745             : {
     746           0 :         uint64_t el_blk = be64_to_cpu(*data_ptr);
     747           0 :         struct lgfs2_buffer_head *bh = NULL;
     748           0 :         int error = 0;
     749             : 
     750           0 :         if (!valid_block_ip(ip, el_blk)) {
     751           0 :                 log_err(_("Inode #%"PRIu64" (0x%"PRIx64"): extended attribute block "
     752             :                           "%"PRIu64" (0x%"PRIx64") has an extended leaf block #%"PRIu64" "
     753             :                           "(0x%"PRIx64") that is invalid or out of range.\n"),
     754             :                         ip->i_num.in_addr, ip->i_num.in_addr, ip->i_eattr, ip->i_eattr, el_blk, el_blk);
     755           0 :                 fsck_blockmap_set(cx, ip, ip->i_eattr, _("bad (out of range) Extended Attribute "),
     756             :                                   GFS2_BLKST_UNLINKED);
     757           0 :                 error = 1;
     758             :         } else {
     759           0 :                 error = check_ealeaf_block(cx, ip, el_blk, GFS2_METATYPE_ED, &bh,
     760             :                                            private);
     761             :         }
     762           0 :         if (bh)
     763           0 :                 lgfs2_brelse(bh);
     764           0 :         if (error) {
     765           0 :                 log_err(_("Bad extended attribute found at block %"PRIu64" (0x%"PRIx64")"),
     766             :                         be64_to_cpu(*data_ptr), be64_to_cpu(*data_ptr));
     767           0 :                 if (query(cx, _("Repair the bad Extended Attribute? (y/n) "))) {
     768           0 :                         ea_hdr->ea_num_ptrs = i;
     769           0 :                         ea_hdr->ea_data_len = cpu_to_be32(tot_ealen);
     770           0 :                         *data_ptr = 0;
     771           0 :                         lgfs2_bmodified(leaf_bh);
     772             :                         /* Endianness doesn't matter in this case because it's
     773             :                            a single byte. */
     774           0 :                         fsck_blockmap_set(cx, ip, ip->i_eattr,
     775             :                                           _("extended attribute"),
     776             :                                           GFS2_BLKST_USED);
     777           0 :                         log_err( _("The EA was fixed.\n"));
     778           0 :                         error = 0;
     779             :                 } else {
     780           0 :                         error = 1;
     781           0 :                         log_err( _("The bad EA was not fixed.\n"));
     782             :                 }
     783             :         }
     784           0 :         return error;
     785             : }
     786             : 
     787           0 : static int p1_check_eattr_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     788             :                             uint64_t parent, struct lgfs2_buffer_head **bh,
     789             :                             void *private)
     790             : {
     791           0 :         if (!valid_block_ip(ip, block)) {
     792           0 :                 log_warn(_("Inode #%"PRIu64" (0x%"PRIx64"): extended attribute leaf "
     793             :                            "block #%"PRIu64" (0x%"PRIx64") is invalid or out of "
     794             :                            "range.\n"),
     795             :                          ip->i_num.in_addr, ip->i_num.in_addr, block, block);
     796           0 :                 fsck_blockmap_set(cx, ip, ip->i_eattr, _("bad (out of range) extended attribute leaf"),
     797             :                                   GFS2_BLKST_UNLINKED);
     798           0 :                 return 1;
     799             :         }
     800           0 :         return check_ealeaf_block(cx, ip, block, GFS2_METATYPE_EA, bh, private);
     801             : }
     802             : 
     803           0 : static int ask_remove_eattr_entry(struct fsck_cx *cx,
     804             :                                   struct lgfs2_buffer_head *leaf_bh,
     805             :                                   struct gfs2_ea_header *curr,
     806             :                                   struct gfs2_ea_header *prev,
     807             :                                   int fix_curr, int fix_curr_len)
     808             : {
     809           0 :         if (!query(cx, _("Remove the bad Extended Attribute entry? (y/n) "))) {
     810           0 :                 log_err( _("Bad Extended Attribute not removed.\n"));
     811           0 :                 return 0;
     812             :         }
     813           0 :         if (fix_curr)
     814           0 :                 curr->ea_flags |= GFS2_EAFLAG_LAST;
     815           0 :         if (fix_curr_len) {
     816           0 :                 uint32_t max_size = cx->sdp->sd_bsize;
     817           0 :                 uint32_t offset = (uint32_t)(((unsigned long)curr) -
     818           0 :                                              ((unsigned long)leaf_bh->b_data));
     819           0 :                 curr->ea_rec_len = cpu_to_be32(max_size - offset);
     820             :         }
     821           0 :         if (!prev)
     822           0 :                 curr->ea_type = GFS2_EATYPE_UNUSED;
     823             :         else {
     824           0 :                 uint32_t tmp32 = be32_to_cpu(curr->ea_rec_len) +
     825           0 :                         be32_to_cpu(prev->ea_rec_len);
     826           0 :                 prev->ea_rec_len = cpu_to_be32(tmp32);
     827           0 :                 if (curr->ea_flags & GFS2_EAFLAG_LAST)
     828           0 :                         prev->ea_flags |= GFS2_EAFLAG_LAST;
     829             :         }
     830           0 :         log_err(_("Bad Extended Attribute at block %"PRIu64" (0x%"PRIx64") removed.\n"),
     831             :                 leaf_bh->b_blocknr, leaf_bh->b_blocknr);
     832           0 :         lgfs2_bmodified(leaf_bh);
     833           0 :         return 1;
     834             : }
     835             : 
     836           0 : static int eatype_max(unsigned fs_format)
     837             : {
     838           0 :         int max = 4;
     839           0 :         if (fs_format < 1802)
     840           0 :                 max = 3;
     841           0 :         return max;
     842             : }
     843             : 
     844           0 : static int p1_check_eattr_entry(struct fsck_cx *cx, struct lgfs2_inode *ip,
     845             :                                struct lgfs2_buffer_head *leaf_bh,
     846             :                                struct gfs2_ea_header *ea_hdr,
     847             :                                struct gfs2_ea_header *ea_hdr_prev,
     848             :                                void *private)
     849             : {
     850           0 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     851             :         char ea_name[256];
     852           0 :         uint32_t offset_limit = sdp->sd_bsize - sizeof(struct gfs2_ea_header);
     853           0 :         uint32_t offset = (uint32_t)(((unsigned long)ea_hdr) -
     854           0 :                                      ((unsigned long)leaf_bh->b_data));
     855           0 :         uint32_t rec_len = be32_to_cpu(ea_hdr->ea_rec_len);
     856             :         uint32_t avail_size;
     857             :         int max_ptrs;
     858             : 
     859           0 :         if (!ea_hdr->ea_name_len){
     860           0 :                 log_err( _("EA has name length of zero\n"));
     861           0 :                 return ask_remove_eattr_entry(cx, leaf_bh, ea_hdr,
     862             :                                               ea_hdr_prev, 1, 1);
     863             :         }
     864           0 :         if (offset + rec_len > offset_limit &&
     865           0 :             offset + rec_len != sdp->sd_bsize) {
     866           0 :                 log_err( _("EA record length too long (%"PRIu32"+%"PRIu32")\n"),
     867             :                         offset, rec_len);
     868           0 :                 return ask_remove_eattr_entry(cx, leaf_bh, ea_hdr,
     869             :                                               ea_hdr_prev, 1, 1);
     870             :         }
     871           0 :         if (offset + rec_len == sdp->sd_bsize &&
     872           0 :            (ea_hdr->ea_flags & GFS2_EAFLAG_LAST) == 0){
     873           0 :                 log_err( _("last EA has no last entry flag\n"));
     874           0 :                 return ask_remove_eattr_entry(cx, leaf_bh, ea_hdr,
     875             :                                               ea_hdr_prev, 0, 0);
     876             :         }
     877           0 :         if (!ea_hdr->ea_name_len){
     878           0 :                 log_err( _("EA has name length of zero\n"));
     879           0 :                 return ask_remove_eattr_entry(cx, leaf_bh, ea_hdr,
     880             :                                               ea_hdr_prev, 0, 0);
     881             :         }
     882             : 
     883           0 :         memset(ea_name, 0, sizeof(ea_name));
     884           0 :         strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
     885           0 :                 ea_hdr->ea_name_len);
     886             : 
     887           0 :         if (ea_hdr->ea_type > eatype_max(sdp->sd_fs_format) &&
     888           0 :            ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
     889             :                 /* Skip invalid entry */
     890           0 :                 log_err(_("EA (%s) type is invalid (%d > %d).\n"),
     891             :                         ea_name, ea_hdr->ea_type, eatype_max(sdp->sd_fs_format));
     892           0 :                 return ask_remove_eattr_entry(cx, leaf_bh, ea_hdr,
     893             :                                               ea_hdr_prev, 0, 0);
     894             :         }
     895             : 
     896           0 :         if (!ea_hdr->ea_num_ptrs)
     897           0 :                 return 0;
     898             : 
     899           0 :         avail_size = sdp->sd_bsize - sizeof(struct gfs2_meta_header);
     900           0 :         max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len)+avail_size-1)/avail_size;
     901             : 
     902           0 :         if (max_ptrs > ea_hdr->ea_num_ptrs) {
     903           0 :                 log_err(_("EA (%s) has incorrect number of pointers.\n"),
     904             :                         ea_name);
     905           0 :                 log_err(_("  Required:  %d\n  Reported:  %d\n"),
     906             :                         max_ptrs, ea_hdr->ea_num_ptrs);
     907           0 :                 return ask_remove_eattr_entry(cx, leaf_bh, ea_hdr,
     908             :                                               ea_hdr_prev, 0, 0);
     909             :         } else {
     910           0 :                 log_debug( _("  Pointers Required: %d\n  Pointers Reported: %d\n"),
     911             :                            max_ptrs, ea_hdr->ea_num_ptrs);
     912             :         }
     913           0 :         return 0;
     914             : }
     915             : 
     916             : /**
     917             :  * Check for massive amounts of pointer corruption.  If the block has
     918             :  * lots of out-of-range pointers, we can't trust any of the pointers.
     919             :  * For example, a stray pointer with a value of 0x1d might be
     920             :  * corruption/nonsense, and if so, we don't want to delete an
     921             :  * important file (like master or the root directory) because of it.
     922             :  * We need to check for a large number of bad pointers BEFORE we start
     923             :  * messing with them because we don't want to mark a block as a
     924             :  * duplicate (for example) until we know if the pointers in general can
     925             :  * be trusted. Thus it needs to be in a separate loop.
     926             :  * Returns: 0 if good range, otherwise != 0
     927             :  */
     928             : enum b_types { BTYPE_META, BTYPE_LEAF, BTYPE_DATA, BTYPE_IEATTR, BTYPE_EATTR};
     929             : static const char *btypes[5] = {
     930             :         "metadata", "leaf", "data", "indirect extended attribute",
     931             :         "extended attribute" };
     932             : 
     933     1981046 : static int rangecheck_block(struct lgfs2_inode *ip, uint64_t block,
     934             :                             struct lgfs2_buffer_head **bh, enum b_types btype,
     935             :                             void *private)
     936             : {
     937     1981046 :         long *bad_pointers = (long *)private;
     938             :         int q;
     939             : 
     940     1981046 :         if (!valid_block_ip(ip, block)) {
     941           0 :                 (*bad_pointers)++;
     942           0 :                 log_info(_("Bad %s block pointer (invalid or out of range "
     943             :                            "#%ld) found in inode %"PRIu64" (0x%"PRIx64").\n"),
     944             :                          btypes[btype], *bad_pointers, ip->i_num.in_addr, ip->i_num.in_addr);
     945           0 :                 if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
     946           0 :                         return META_IS_GOOD;
     947             :                 else
     948           0 :                         return META_ERROR; /* Exits check_metatree quicker */
     949             :         }
     950             :         /* See how many duplicate blocks it has */
     951     1981046 :         q = block_type(bl, block);
     952     1981046 :         if (q != GFS2_BLKST_FREE) {
     953           0 :                 (*bad_pointers)++;
     954           0 :                 log_info(_("Duplicated %s block pointer (violation %ld, block %"PRIu64
     955             :                            " (0x%"PRIx64")) found in inode %"PRIu64" (0x%"PRIx64").\n"),
     956             :                           btypes[btype], *bad_pointers, block, block, ip->i_num.in_addr, ip->i_num.in_addr);
     957           0 :                 if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
     958           0 :                         return META_IS_GOOD;
     959             :                 else {
     960           0 :                         log_debug(_("Inode 0x%"PRIx64" bad pointer tolerance "
     961             :                                     "exceeded: block 0x%"PRIx64".\n"),
     962             :                                   ip->i_num.in_addr, block);
     963           0 :                         return META_ERROR; /* Exits check_metatree quicker */
     964             :                 }
     965             :         }
     966     1981046 :         return META_IS_GOOD;
     967             : }
     968             : 
     969        7361 : static int rangecheck_metadata(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
     970             :                                int *is_valid, int *was_duplicate, void *private)
     971             : {
     972        7361 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     973        7361 :         uint64_t block = iptr_block(iptr);
     974             : 
     975        7361 :         *is_valid = 1;
     976        7361 :         *was_duplicate = 0;
     977        7361 :         return rangecheck_block(ip, block, bh, BTYPE_META, private);
     978             : }
     979             : 
     980           9 : static int rangecheck_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     981             :                            void *private)
     982             : {
     983           9 :         return rangecheck_block(ip, block, NULL, BTYPE_LEAF, private);
     984             : }
     985             : 
     986     1973676 : static int rangecheck_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
     987             :                            uint64_t block, void *private,
     988             :                            struct lgfs2_buffer_head *bh, __be64 *ptr)
     989             : {
     990     1973676 :         return rangecheck_block(ip, block, NULL, BTYPE_DATA, private);
     991             : }
     992             : 
     993           0 : static int rangecheck_eattr_indir(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     994             :                                   uint64_t parent,
     995             :                                   struct lgfs2_buffer_head **bh, void *private)
     996             : {
     997           0 :         return rangecheck_block(ip, block, NULL, BTYPE_IEATTR, private);
     998             : }
     999             : 
    1000           0 : static int rangecheck_eattr_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
    1001             :                                  uint64_t parent, struct lgfs2_buffer_head **bh,
    1002             :                                  void *private)
    1003             : {
    1004           0 :         return rangecheck_block(ip, block, NULL, BTYPE_EATTR, private);
    1005             : }
    1006             : 
    1007             : static struct metawalk_fxns rangecheck_fxns = {
    1008             :         .private = NULL,
    1009             :         .readahead = 1,
    1010             :         .check_metalist = rangecheck_metadata,
    1011             :         .check_data = rangecheck_data,
    1012             :         .check_leaf = rangecheck_leaf,
    1013             :         .check_eattr_indir = rangecheck_eattr_indir,
    1014             :         .check_eattr_leaf = rangecheck_eattr_leaf,
    1015             :         .delete_block = p1_delete_block,
    1016             : };
    1017             : 
    1018             : static struct metawalk_fxns eattr_undo_fxns = {
    1019             :         .private = NULL,
    1020             :         .check_eattr_indir = undo_eattr_indir_or_leaf,
    1021             :         .check_eattr_leaf = undo_eattr_indir_or_leaf,
    1022             :         .finish_eattr_indir = p1_finish_eattr_indir,
    1023             :         .delete_block = p1_delete_block,
    1024             : };
    1025             : /* set_ip_blockmap - set the blockmap for a dinode
    1026             :  *
    1027             :  * returns: 0 if no error, -EINVAL if dinode has a bad mode, -EPERM on error
    1028             :  */
    1029         700 : static int set_ip_blockmap(struct fsck_cx *cx, struct lgfs2_inode *ip)
    1030             : {
    1031         700 :         uint64_t block = ip->i_bh->b_blocknr;
    1032             :         struct lgfs2_inum no;
    1033             :         uint32_t mode;
    1034             :         const char *ty;
    1035             : 
    1036         700 :         mode = ip->i_mode & S_IFMT;
    1037             : 
    1038         700 :         switch (mode) {
    1039         224 :         case S_IFDIR:
    1040         224 :                 ty = "directory";
    1041         224 :                 break;
    1042         476 :         case S_IFREG:
    1043         476 :                 ty = "file";
    1044         476 :                 break;
    1045           0 :         case S_IFLNK:
    1046           0 :                 ty = "symlink";
    1047           0 :                 break;
    1048           0 :         case S_IFBLK:
    1049           0 :                 ty = "block device";
    1050           0 :                 break;
    1051           0 :         case S_IFCHR:
    1052           0 :                 ty = "character device";
    1053           0 :                 break;
    1054           0 :         case S_IFIFO:
    1055           0 :                 ty = "fifo";
    1056           0 :                 break;
    1057           0 :         case S_IFSOCK:
    1058           0 :                 ty = "socket";
    1059           0 :                 break;
    1060           0 :         default:
    1061           0 :                 return -EINVAL;
    1062             :         }
    1063         700 :         no = ip->i_num;
    1064         700 :         if (fsck_blockmap_set(cx, ip, block, ty, GFS2_BLKST_DINODE) ||
    1065         224 :             (mode == S_IFDIR && !dirtree_insert(cx, no))) {
    1066           0 :                 stack;
    1067           0 :                 return -EPERM;
    1068             :         }
    1069         700 :         return 0;
    1070             : }
    1071             : 
    1072           0 : static int alloc_metalist(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
    1073             :                           int *is_valid, int *was_duplicate, void *private)
    1074             : {
    1075           0 :         const char *desc = (const char *)private;
    1076           0 :         struct lgfs2_inode *ip = iptr.ipt_ip;
    1077           0 :         uint64_t block = iptr_block(iptr);
    1078             :         int q;
    1079             : 
    1080             :         /* No need to range_check here--if it was added, it's in range. */
    1081             :         /* We can't check the bitmap here because this function is called
    1082             :            after the bitmap has been set but before the blockmap has. */
    1083           0 :         *is_valid = 1;
    1084           0 :         *was_duplicate = 0;
    1085           0 :         *bh = lgfs2_bread(ip->i_sbd, block);
    1086           0 :         q = bitmap_type(ip->i_sbd, block);
    1087           0 :         if (q == GFS2_BLKST_FREE) {
    1088           0 :                 log_debug(_("%s reference to new metadata block %"PRIu64" (0x%"PRIx64") is now marked as indirect.\n"),
    1089             :                           desc, block, block);
    1090           0 :                 blockmap_set(bl, block, GFS2_BLKST_USED);
    1091             :         }
    1092           0 :         return META_IS_GOOD;
    1093             : }
    1094             : 
    1095           0 : static int alloc_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
    1096             :                       uint64_t block, void *private,
    1097             :                       struct lgfs2_buffer_head *bh, __be64 *ptr)
    1098             : {
    1099             :         int q;
    1100           0 :         const char *desc = (const char *)private;
    1101             : 
    1102             :         /* No need to range_check here--if it was added, it's in range. */
    1103             :         /* We can't check the bitmap here because this function is called
    1104             :            after the bitmap has been set but before the blockmap has. */
    1105           0 :         q = bitmap_type(ip->i_sbd, block);
    1106           0 :         if (q == GFS2_BLKST_FREE) {
    1107           0 :                 log_debug(_("%s reference to new data block %"PRIu64" (0x%"PRIx64") is now marked as data.\n"),
    1108             :                           desc, block, block);
    1109           0 :                 blockmap_set(bl, block, GFS2_BLKST_USED);
    1110             :         }
    1111           0 :         return 0;
    1112             : }
    1113             : 
    1114           0 : static int alloc_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, void *private)
    1115             : {
    1116             :         int q;
    1117             : 
    1118             :         /* No need to range_check here--if it was added, it's in range. */
    1119             :         /* We can't check the bitmap here because this function is called
    1120             :            after the bitmap has been set but before the blockmap has. */
    1121           0 :         q = bitmap_type(ip->i_sbd, block);
    1122           0 :         if (q == GFS2_BLKST_FREE)
    1123           0 :                 fsck_blockmap_set(cx, ip, block, "newly allocated leaf",
    1124             :                                   GFS2_BLKST_USED);
    1125           0 :         return 0;
    1126             : }
    1127             : 
    1128             : static struct metawalk_fxns alloc_fxns = {
    1129             :         .private = NULL,
    1130             :         .check_leaf = alloc_leaf,
    1131             :         .check_metalist = alloc_metalist,
    1132             :         .check_data = alloc_data,
    1133             :         .check_eattr_indir = NULL,
    1134             :         .check_eattr_leaf = NULL,
    1135             :         .check_dentry = NULL,
    1136             :         .check_eattr_entry = NULL,
    1137             :         .check_eattr_extentry = NULL,
    1138             :         .finish_eattr_indir = NULL,
    1139             :         .delete_block = p1_delete_block,
    1140             : };
    1141             : 
    1142             : /*
    1143             :  * pass1_check_metatree - wrapper function for check_metatree
    1144             :  *
    1145             :  * Generic function check_metatree sets the bitmap values, but not the
    1146             :  * corresponding values in the blockmap. If we get an error, the inode will
    1147             :  * have been freed in the bitmap. We need to set the inode address as free
    1148             :  * as well.
    1149             :  */
    1150        1407 : static int pass1_check_metatree(struct fsck_cx *cx, struct lgfs2_inode *ip,
    1151             :                                 struct metawalk_fxns *pass)
    1152             : {
    1153             :         int error;
    1154             : 
    1155        1407 :         error = check_metatree(cx, ip, pass);
    1156        1407 :         if (error)
    1157           0 :                 blockmap_set(bl, ip->i_num.in_addr, GFS2_BLKST_FREE);
    1158        1407 :         return error;
    1159             : }
    1160             : 
    1161             : /*
    1162             :  * reprocess_inode - fixes the blockmap to match the bitmap due to an
    1163             :  *                   unexpected block allocation via libgfs2.
    1164             :  *
    1165             :  * The problem we're trying to overcome here is when a new block must be
    1166             :  * added to a dinode because of a write.  This will happen when lost+found
    1167             :  * needs a new indirect block for its hash table.  In that case, the write
    1168             :  * causes a new block to be assigned in the bitmap but that block is not yet
    1169             :  * accurately reflected in the fsck blockmap.  We need to compensate here.
    1170             :  *
    1171             :  * We can't really use fsck_blockmap_set here because the new block
    1172             :  * was already allocated by libgfs2 and therefore it took care of
    1173             :  * the rgrp free space variable.  fsck_blockmap_set adjusts the free space
    1174             :  * in the rgrp according to the change, which has already been done.
    1175             :  * So it's only our blockmap that now disagrees with the rgrp bitmap, so we
    1176             :  * need to fix only that.
    1177             :  */
    1178           0 : static void reprocess_inode(struct fsck_cx *cx, struct lgfs2_inode *ip, const char *desc)
    1179             : {
    1180             :         int error;
    1181             : 
    1182           0 :         alloc_fxns.private = (void *)desc;
    1183           0 :         log_info(_("%s inode %"PRIu64" (0x%"PRIx64") had blocks added; reprocessing "
    1184             :                    "its metadata tree at height=%d.\n"), desc,
    1185             :                  ip->i_num.in_addr, ip->i_num.in_addr, ip->i_height);
    1186           0 :         error = pass1_check_metatree(cx, ip, &alloc_fxns);
    1187           0 :         if (error)
    1188           0 :                 log_err( _("Error %d reprocessing the %s metadata tree.\n"),
    1189             :                          error, desc);
    1190           0 : }
    1191             : 
    1192             : /*
    1193             :  * handle_ip - process an incore structure representing a dinode.
    1194             :  */
    1195         700 : static int handle_ip(struct fsck_cx *cx, struct lgfs2_inode *ip)
    1196             : {
    1197             :         int error;
    1198         700 :         struct block_count bc = {0};
    1199             :         long bad_pointers;
    1200         700 :         uint64_t lf_blks = 0;
    1201             : 
    1202         700 :         bad_pointers = 0L;
    1203             : 
    1204             :         /* First, check the metadata for massive amounts of pointer corruption.
    1205             :            Such corruption can only lead us to ruin trying to clean it up,
    1206             :            so it's better to check it up front and delete the inode if
    1207             :            there is corruption. */
    1208         700 :         rangecheck_fxns.private = &bad_pointers;
    1209         700 :         error = pass1_check_metatree(cx, ip, &rangecheck_fxns);
    1210         700 :         if (bad_pointers > BAD_POINTER_TOLERANCE) {
    1211           0 :                 log_err(_("Error: inode %"PRIu64" (0x%"PRIx64") has more than %d bad pointers.\n"),
    1212             :                         ip->i_num.in_addr, ip->i_num.in_addr, BAD_POINTER_TOLERANCE);
    1213           0 :                 fsck_blockmap_set(cx, ip, ip->i_num.in_addr, _("badly corrupt"), GFS2_BLKST_FREE);
    1214           0 :                 return 0;
    1215             :         }
    1216             : 
    1217         700 :         error = set_ip_blockmap(cx, ip);
    1218         700 :         if (error == -EINVAL) {
    1219             :                 /* We found a dinode that has an invalid mode. At this point
    1220             :                    set_ip_blockmap returned an error, which means it never
    1221             :                    got inserted into the inode tree. Since we haven't even
    1222             :                    processed its metadata with pass1_fxns, none of its
    1223             :                    metadata will be flagged as metadata or data blocks yet.
    1224             :                    Therefore, we don't need to invalidate anything. */
    1225           0 :                 fsck_blockmap_set(cx, ip, ip->i_num.in_addr, _("invalid mode"), GFS2_BLKST_FREE);
    1226           0 :                 return 0;
    1227         700 :         } else if (error)
    1228           0 :                 goto bad_dinode;
    1229             : 
    1230         700 :         if (set_di_nlink(cx, ip))
    1231           0 :                 goto bad_dinode;
    1232             : 
    1233         700 :         if (lf_dip)
    1234           0 :                 lf_blks = lf_dip->i_blocks;
    1235             : 
    1236         700 :         pass1_fxns.private = &bc;
    1237         700 :         error = pass1_check_metatree(cx, ip, &pass1_fxns);
    1238             : 
    1239             :         /* Pass1 may have added some blocks to lost+found by virtue of leafs
    1240             :            that were misplaced. If it did, we need to reprocess lost+found
    1241             :            to correctly account for its blocks. */
    1242         700 :         if (lf_dip && lf_dip->i_blocks != lf_blks)
    1243           0 :                 reprocess_inode(cx, lf_dip, "lost+found");
    1244             : 
    1245             :         /* We there was an error, we return 0 because we want fsck to continue
    1246             :            and analyze the other dinodes as well. */
    1247         700 :         if (fsck_abort)
    1248           0 :                 return 0;
    1249             : 
    1250         700 :         if (!error) {
    1251         700 :                 error = check_inode_eattr(cx, ip, &pass1_fxns);
    1252             : 
    1253         700 :                 if (error) {
    1254           0 :                         if (!query(cx, _("Clear the bad Extended Attributes? (y/n) "))) {
    1255           0 :                                 log_err(_("The bad Extended Attributes were not fixed.\n"));
    1256           0 :                                 return 0;
    1257             :                         }
    1258           0 :                         log_err(_("Clearing the bad Extended Attributes in "
    1259             :                                   "inode %"PRIu64" (0x%"PRIx64").\n"),
    1260             :                                 ip->i_num.in_addr, ip->i_num.in_addr);
    1261           0 :                         eattr_undo_fxns.private = &bc;
    1262           0 :                         check_inode_eattr(cx, ip, &eattr_undo_fxns);
    1263           0 :                         ask_remove_inode_eattr(cx, ip, &bc);
    1264           0 :                         return 1;
    1265             :                 }
    1266             :         }
    1267             : 
    1268         700 :         if (ip->i_blocks != (1 + bc.indir_count + bc.data_count + bc.ea_count)) {
    1269           0 :                 log_err(_("Inode #%"PRIu64" (0x%"PRIx64"): Ondisk block count (%"PRIu64
    1270             :                         ") does not match what fsck found (%"PRIu64")\n"),
    1271             :                         ip->i_num.in_addr, ip->i_num.in_addr, ip->i_blocks, 1 + bc.indir_count +
    1272             :                         bc.data_count + bc.ea_count);
    1273           0 :                 log_info(_("inode has: %"PRIu64", but fsck counts: Dinode:1 + "
    1274             :                            "indir:%"PRIu64" + data: %"PRIu64" + ea: %"PRIu64"\n"),
    1275             :                          ip->i_blocks, bc.indir_count, bc.data_count, bc.ea_count);
    1276           0 :                 if (query(cx, _("Fix ondisk block count? (y/n) "))) {
    1277           0 :                         ip->i_blocks = 1 + bc.indir_count + bc.data_count + bc.ea_count;
    1278           0 :                         lgfs2_bmodified(ip->i_bh);
    1279           0 :                         log_err(_("Block count for #%"PRIu64" (0x%"PRIx64") fixed\n"),
    1280             :                                 ip->i_num.in_addr, ip->i_num.in_addr);
    1281             :                 } else
    1282           0 :                         log_err(_("Bad block count for #%"PRIu64" (0x%"PRIx64") not fixed\n"),
    1283             :                                 ip->i_num.in_addr, ip->i_num.in_addr);
    1284             :         }
    1285             : 
    1286         700 :         return 0;
    1287           0 : bad_dinode:
    1288           0 :         stack;
    1289           0 :         return -1;
    1290             : }
    1291             : 
    1292         700 : static void check_i_goal(struct fsck_cx *cx, struct lgfs2_inode *ip)
    1293             : {
    1294         700 :         if (ip->i_flags & GFS2_DIF_SYSTEM)
    1295         644 :                 return;
    1296             : 
    1297          56 :         if (ip->i_goal_meta <= LGFS2_SB_ADDR(cx->sdp) ||
    1298          55 :             ip->i_goal_meta > cx->sdp->fssize) {
    1299           1 :                 log_err(_("Inode #%"PRIu64" (0x%"PRIx64"): Bad allocation goal block "
    1300             :                           "found: %"PRIu64" (0x%"PRIx64")\n"),
    1301             :                         ip->i_num.in_addr, ip->i_num.in_addr, ip->i_goal_meta, ip->i_goal_meta);
    1302           1 :                 if (query(cx, _("Fix goal block in inode #%"PRIu64" (0x%"PRIx64")? (y/n) "),
    1303             :                           ip->i_num.in_addr, ip->i_num.in_addr)) {
    1304           1 :                         ip->i_goal_meta = ip->i_num.in_addr;
    1305           1 :                         lgfs2_bmodified(ip->i_bh);
    1306             :                 } else
    1307           0 :                         log_err(_("Allocation goal block in inode #%"PRIu64
    1308             :                                   " (0x%"PRIx64") not fixed\n"),
    1309             :                                 ip->i_num.in_addr, ip->i_num.in_addr);
    1310             :         }
    1311             : }
    1312             : 
    1313             : /*
    1314             :  * handle_di - This is now a wrapper function that takes a lgfs2_buffer_head
    1315             :  *             and calls handle_ip, which takes an in-code dinode structure.
    1316             :  */
    1317         189 : static int handle_di(struct fsck_cx *cx, struct lgfs2_rgrp_tree *rgd,
    1318             :                      struct lgfs2_buffer_head *bh)
    1319             : {
    1320         189 :         int error = 0;
    1321         189 :         uint64_t block = bh->b_blocknr;
    1322             :         struct lgfs2_inode *ip;
    1323             : 
    1324         189 :         ip = fsck_inode_get(cx->sdp, rgd, bh);
    1325             : 
    1326         189 :         if (ip->i_num.in_addr != block) {
    1327           0 :                 log_err(_("Inode #%"PRIu64" (0x%"PRIx64"): Bad inode address found: %"PRIu64
    1328             :                           " (0x%"PRIx64")\n"),
    1329             :                         block, block, ip->i_num.in_addr, ip->i_num.in_addr);
    1330           0 :                 if (query(cx, _("Fix address in inode at block #%"PRIu64" (0x%"PRIx64")? (y/n) "),
    1331             :                           block, block)) {
    1332           0 :                         ip->i_num.in_addr = ip->i_num.in_formal_ino = block;
    1333           0 :                         lgfs2_bmodified(ip->i_bh);
    1334             :                 } else
    1335           0 :                         log_err(_("Address in inode at block #%"PRIu64" (0x%"PRIx64" not fixed\n"),
    1336             :                                 block, block);
    1337             :         }
    1338         189 :         check_i_goal(cx, ip);
    1339         189 :         error = handle_ip(cx, ip);
    1340         189 :         fsck_inode_put(&ip);
    1341         189 :         return error;
    1342             : }
    1343             : 
    1344             : /* Check system inode and verify it's marked "in use" in the bitmap:       */
    1345             : /* Should work for all system inodes: root, master, jindex, per_node, etc. */
    1346             : /* We have to pass the sysinode as ** because the pointer may change out from
    1347             :    under the reference by way of the builder() function.  */
    1348         511 : static int check_system_inode(struct fsck_cx *cx,
    1349             :                               struct lgfs2_inode **sysinode,
    1350             :                               const char *filename,
    1351             :                               int builder(struct lgfs2_sbd *sdp), int isdir,
    1352             :                               struct lgfs2_inode *sysdir, int needs_sysbit)
    1353             : {
    1354         511 :         uint64_t iblock = 0;
    1355         511 :         struct dir_status ds = {0};
    1356         511 :         int error, err = 0;
    1357             : 
    1358         511 :         log_info( _("Checking system inode '%s'\n"), filename);
    1359         511 :         if (*sysinode) {
    1360             :                 /* Read in the system inode, look at its dentries, and start
    1361             :                  * reading through them */
    1362         510 :                 iblock = (*sysinode)->i_num.in_addr;
    1363         510 :                 log_info(_("System inode for '%s' is located at block %"PRIu64" (0x%"PRIx64")\n"),
    1364             :                          filename, iblock, iblock);
    1365         510 :                 if (lgfs2_check_meta((*sysinode)->i_bh->b_data, GFS2_METATYPE_DI)) {
    1366           0 :                         log_err(_("Found invalid system dinode at block %"PRIu64" (0x%"PRIx64")\n"),
    1367             :                                 iblock, iblock);
    1368           0 :                         blockmap_set(bl, iblock, GFS2_BLKST_FREE);
    1369           0 :                         check_n_fix_bitmap(cx, (*sysinode)->i_rgd, iblock, 0,
    1370             :                                            GFS2_BLKST_FREE);
    1371           0 :                         lgfs2_inode_put(sysinode);
    1372             :                 }
    1373             :         }
    1374         511 :         if (*sysinode) {
    1375         510 :                 ds.q = block_type(bl, iblock);
    1376             :                 /* If the inode exists but the block is marked free, we might
    1377             :                    be recovering from a corrupt bitmap.  In that case, don't
    1378             :                    rebuild the inode.  Just reuse the inode and fix the
    1379             :                    bitmap. */
    1380         510 :                 if (ds.q == GFS2_BLKST_FREE) {
    1381           0 :                         log_info( _("The inode exists but the block is not "
    1382             :                                     "marked 'in use'; fixing it.\n"));
    1383           0 :                         fsck_blockmap_set(cx, *sysinode, (*sysinode)->i_num.in_addr,
    1384             :                                           filename, GFS2_BLKST_DINODE);
    1385           0 :                         ds.q = GFS2_BLKST_DINODE;
    1386           0 :                         if (isdir) {
    1387           0 :                                 struct lgfs2_inum no = (*sysinode)->i_num;
    1388           0 :                                 dirtree_insert(cx, no);
    1389             :                         }
    1390             :                 }
    1391             :                 /* Make sure it's marked as a system file/directory */
    1392         510 :                 if (needs_sysbit &&
    1393         454 :                     !((*sysinode)->i_flags & GFS2_DIF_SYSTEM)) {
    1394           0 :                         log_err( _("System inode %s is missing the 'system' "
    1395             :                                    "flag. It should be rebuilt.\n"), filename);
    1396           0 :                         if (sysdir && query(cx, _("Delete the corrupt %s system "
    1397             :                                               "inode? (y/n) "), filename)) {
    1398           0 :                                 lgfs2_inode_put(sysinode);
    1399           0 :                                 lgfs2_dirent_del(sysdir, filename,
    1400           0 :                                                 strlen(filename));
    1401             :                                 /* Set the blockmap (but not bitmap) back to
    1402             :                                    'free' so that it gets checked like any
    1403             :                                    normal dinode. */
    1404           0 :                                 blockmap_set(bl, iblock, GFS2_BLKST_FREE);
    1405           0 :                                 log_err( _("Removed system inode \"%s\".\n"),
    1406             :                                          filename);
    1407             :                         }
    1408             :                 }
    1409             :         } else
    1410           1 :                 log_info( _("System inode for '%s' is corrupt or missing.\n"),
    1411             :                           filename);
    1412             :         /* If there are errors with the inode here, we need to create a new
    1413             :            inode and get it all setup - of course, everything will be in
    1414             :            lost+found then, but we *need* our system inodes before we can
    1415             :            do any of that. */
    1416         511 :         if (!(*sysinode) || ds.q != GFS2_BLKST_DINODE) {
    1417           1 :                 log_err(_("Invalid or missing %s system inode (is '%s', "
    1418             :                           "should be '%s').\n"), filename,
    1419             :                         block_type_string(ds.q),
    1420             :                         block_type_string(GFS2_BLKST_DINODE));
    1421           1 :                 if (query(cx, _("Create new %s system inode? (y/n) "), filename)) {
    1422           1 :                         log_err( _("Rebuilding system file \"%s\"\n"),
    1423             :                                  filename);
    1424           1 :                         error = builder(cx->sdp);
    1425           1 :                         if (error || *sysinode == NULL) {
    1426           0 :                                 log_err( _("Error rebuilding system "
    1427             :                                            "inode %s: Cannot continue\n"),
    1428             :                                          filename);
    1429           0 :                                 return error;
    1430             :                         }
    1431           1 :                         if (*sysinode == cx->sdp->md.jiinode)
    1432           0 :                                 ji_update(cx->sdp);
    1433           1 :                         fsck_blockmap_set(cx, *sysinode, (*sysinode)->i_num.in_addr,
    1434             :                                           filename, GFS2_BLKST_DINODE);
    1435           1 :                         ds.q = GFS2_BLKST_DINODE;
    1436           1 :                         if (isdir) {
    1437           0 :                                 struct lgfs2_inum no = (*sysinode)->i_num;
    1438           0 :                                 dirtree_insert(cx, no);
    1439             :                         }
    1440             :                 } else {
    1441           0 :                         log_err( _("Cannot continue without valid %s inode\n"),
    1442             :                                 filename);
    1443           0 :                         return -1;
    1444             :                 }
    1445             :         }
    1446         511 :         if (is_dir(*sysinode)) {
    1447         224 :                 struct block_count bc = {0};
    1448             : 
    1449         224 :                 sysdir_fxns.private = &bc;
    1450         224 :                 if ((*sysinode)->i_flags & GFS2_DIF_EXHASH)
    1451           7 :                         pass1_check_metatree(cx, *sysinode, &sysdir_fxns);
    1452             :                 else {
    1453         217 :                         err = check_linear_dir(cx, *sysinode, (*sysinode)->i_bh,
    1454             :                                                &sysdir_fxns);
    1455             :                         /* If we encountered an error in our directory check
    1456             :                            we should still call handle_ip, but return the
    1457             :                            error later. */
    1458         217 :                         if (err)
    1459           0 :                                 log_err(_("Error found in %s while checking "
    1460             :                                           "directory entries.\n"), filename);
    1461             :                 }
    1462             :         }
    1463         511 :         check_i_goal(cx, *sysinode);
    1464         511 :         error = handle_ip(cx, *sysinode);
    1465         511 :         return error ? error : err;
    1466             : }
    1467             : 
    1468           1 : static int build_a_journal(struct lgfs2_sbd *sdp)
    1469             : {
    1470             :         char name[256];
    1471           1 :         int err = 0;
    1472             : 
    1473             :         /* First, try to delete the journal if it's in jindex */
    1474           1 :         sprintf(name, "journal%u", sdp->md.journals);
    1475           1 :         lgfs2_dirent_del(sdp->md.jiinode, name, strlen(name));
    1476             :         /* Now rebuild it */
    1477           1 :         err = lgfs2_build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
    1478           1 :         if (err) {
    1479           0 :                 log_crit(_("Error %d building journal\n"), err);
    1480           0 :                 exit(FSCK_ERROR);
    1481             :         }
    1482           1 :         return 0;
    1483             : }
    1484             : 
    1485           0 : int build_per_node(struct lgfs2_sbd *sdp)
    1486             : {
    1487             :         struct lgfs2_inode *per_node;
    1488             :         unsigned int j;
    1489             : 
    1490             :         /* coverity[identity_transfer:SUPPRESS] False positive */
    1491           0 :         per_node = lgfs2_createi(sdp->master_dir, "per_node", S_IFDIR | 0700,
    1492             :                            GFS2_DIF_SYSTEM);
    1493           0 :         if (per_node == NULL) {
    1494           0 :                 log_err(_("Error building '%s': %s\n"), "per_node", strerror(errno));
    1495           0 :                 return -1;
    1496             :         }
    1497           0 :         for (j = 0; j < sdp->md.journals; j++) {
    1498             :                 struct lgfs2_inode *ip;
    1499             : 
    1500             :                 /* coverity[identity_transfer:SUPPRESS] False positive */
    1501           0 :                 ip = lgfs2_build_inum_range(per_node, j);
    1502           0 :                 if (ip == NULL) {
    1503           0 :                         log_err(_("Error building '%s': %s\n"), "inum_range",
    1504             :                                 strerror(errno));
    1505           0 :                         lgfs2_inode_put(&per_node);
    1506           0 :                         return 1;
    1507             :                 }
    1508           0 :                 lgfs2_inode_put(&ip);
    1509             : 
    1510             :                 /* coverity[identity_transfer:SUPPRESS] False positive */
    1511           0 :                 ip = lgfs2_build_statfs_change(per_node, j);
    1512           0 :                 if (ip == NULL) {
    1513           0 :                         log_err(_("Error building '%s': %s\n"), "statfs_change",
    1514             :                                 strerror(errno));
    1515           0 :                         lgfs2_inode_put(&per_node);
    1516           0 :                         return 1;
    1517             :                 }
    1518           0 :                 lgfs2_inode_put(&ip);
    1519             : 
    1520             :                 /* coverity[identity_transfer:SUPPRESS] False positive */
    1521           0 :                 ip = lgfs2_build_quota_change(per_node, j);
    1522           0 :                 if (ip == NULL) {
    1523           0 :                         log_err(_("Error building '%s': %s\n"), "quota_change",
    1524             :                                 strerror(errno));
    1525             :                         /* coverity[deref_arg:SUPPRESS] */
    1526           0 :                         lgfs2_inode_put(&per_node);
    1527           0 :                         return 1;
    1528             :                 }
    1529           0 :                 lgfs2_inode_put(&ip);
    1530             :         }
    1531           0 :         lgfs2_inode_put(&per_node);
    1532           0 :         return 0;
    1533             : }
    1534             : 
    1535           0 : static int build_inum(struct lgfs2_sbd *sdp)
    1536             : {
    1537           0 :         struct lgfs2_inode *ip = lgfs2_build_inum(sdp);
    1538           0 :         if (ip == NULL)
    1539           0 :                 return -1;
    1540           0 :         lgfs2_inode_put(&ip);
    1541           0 :         return 0;
    1542             : }
    1543             : 
    1544           0 : static int build_statfs(struct lgfs2_sbd *sdp)
    1545             : {
    1546           0 :         struct lgfs2_inode *ip = lgfs2_build_statfs(sdp);
    1547           0 :         if (ip == NULL)
    1548           0 :                 return -1;
    1549           0 :         lgfs2_inode_put(&ip);
    1550           0 :         return 0;
    1551             : }
    1552             : 
    1553           0 : static int build_rindex(struct lgfs2_sbd *sdp)
    1554             : {
    1555           0 :         struct lgfs2_inode *ip = lgfs2_build_rindex(sdp);
    1556           0 :         if (ip == NULL)
    1557           0 :                 return -1;
    1558           0 :         lgfs2_inode_put(&ip);
    1559           0 :         return 0;
    1560             : }
    1561             : 
    1562           0 : static int build_quota(struct lgfs2_sbd *sdp)
    1563             : {
    1564           0 :         struct lgfs2_inode *ip = lgfs2_build_quota(sdp);
    1565           0 :         if (ip == NULL)
    1566           0 :                 return -1;
    1567           0 :         lgfs2_inode_put(&ip);
    1568           0 :         return 0;
    1569             : }
    1570             : 
    1571          56 : static int check_system_inodes(struct fsck_cx *cx)
    1572             : {
    1573          56 :         struct lgfs2_sbd *sdp = cx->sdp;
    1574             :         int journal_count;
    1575             : 
    1576             :         /* Mark the master system dinode as a "dinode" in the block map.
    1577             :            All other system dinodes in master will be taken care of by function
    1578             :            resuscitate_metalist.  But master won't since it has no parent.*/
    1579          56 :         fsck_blockmap_set(cx, sdp->master_dir, sdp->master_dir->i_num.in_addr,
    1580             :                           "master", GFS2_BLKST_DINODE);
    1581          56 :         if (check_system_inode(cx, &sdp->master_dir, "master",
    1582             :                                lgfs2_build_master, 1, NULL, 1)) {
    1583           0 :                 stack;
    1584           0 :                 return -1;
    1585             :         }
    1586             :         /* Mark the root dinode as a "dinode" in the block map as we did
    1587             :            for master, since it has no parent. */
    1588          56 :         fsck_blockmap_set(cx, sdp->md.rooti, sdp->md.rooti->i_num.in_addr,
    1589             :                           "root", GFS2_BLKST_DINODE);
    1590          56 :         if (check_system_inode(cx, &sdp->md.rooti, "root", lgfs2_build_root, 1,
    1591             :                                NULL, 0)) {
    1592           0 :                 stack;
    1593           0 :                 return -1;
    1594             :         }
    1595          56 :         if (check_system_inode(cx, &sdp->md.inum, "inum", build_inum, 0,
    1596             :                                sdp->master_dir, 1)) {
    1597           0 :                 stack;
    1598           0 :                 return -1;
    1599             :         }
    1600          56 :         if (check_system_inode(cx, &sdp->md.statfs, "statfs", build_statfs, 0,
    1601             :                                sdp->master_dir, 1)) {
    1602           0 :                 stack;
    1603           0 :                 return -1;
    1604             :         }
    1605          56 :         if (check_system_inode(cx, &sdp->md.jiinode, "jindex", build_jindex,
    1606             :                                1, sdp->master_dir, 1)) {
    1607           0 :                 stack;
    1608           0 :                 return -1;
    1609             :         }
    1610          56 :         if (check_system_inode(cx, &sdp->md.riinode, "rindex", build_rindex,
    1611             :                                0, sdp->master_dir, 1)) {
    1612           0 :                 stack;
    1613           0 :                 return -1;
    1614             :         }
    1615          56 :         if (check_system_inode(cx, &sdp->md.qinode, "quota", build_quota,
    1616             :                                0, sdp->master_dir, 1)) {
    1617           0 :                 stack;
    1618           0 :                 return -1;
    1619             :         }
    1620          56 :         if (check_system_inode(cx, &sdp->md.pinode, "per_node",
    1621             :                                build_per_node, 1, sdp->master_dir, 1)) {
    1622           0 :                 stack;
    1623           0 :                 return -1;
    1624             :         }
    1625             :         /* We have to play a trick on lgfs2_build_journal:  We swap md.journals
    1626             :            in order to keep a count of which journal we need to build. */
    1627          56 :         journal_count = sdp->md.journals;
    1628         119 :         for (sdp->md.journals = 0; sdp->md.journals < journal_count;
    1629          63 :              sdp->md.journals++) {
    1630             :                 char jname[16];
    1631             : 
    1632          63 :                 sprintf(jname, "journal%d", sdp->md.journals);
    1633          63 :                 if (check_system_inode(cx, &sdp->md.journal[sdp->md.journals],
    1634             :                                        jname, build_a_journal, 0,
    1635             :                                        sdp->md.jiinode, 1)) {
    1636           0 :                         stack;
    1637           0 :                         return -1;
    1638             :                 }
    1639             :         }
    1640             : 
    1641          56 :         return 0;
    1642             : }
    1643             : 
    1644         177 : static int pass1_process_bitmap(struct fsck_cx *cx, struct lgfs2_rgrp_tree *rgd, uint64_t *ibuf, unsigned n)
    1645             : {
    1646             :         struct lgfs2_buffer_head *bh;
    1647         177 :         struct lgfs2_sbd *sdp = cx->sdp;
    1648             :         unsigned i;
    1649             :         uint64_t block;
    1650             :         struct lgfs2_inode *ip;
    1651             :         int q;
    1652             :         /* Readahead numbers arrived at by experiment */
    1653         177 :         unsigned rawin = 50;
    1654         177 :         unsigned ralen = 100 * sdp->sd_bsize;
    1655         177 :         unsigned r = 0;
    1656             : 
    1657         878 :         for (i = 0; i < n; i++) {
    1658             :                 int is_inode;
    1659             : 
    1660         701 :                 block = ibuf[i];
    1661             : 
    1662         701 :                 if (r++ == rawin) {
    1663           0 :                         (void)posix_fadvise(sdp->device_fd, block * sdp->sd_bsize, ralen, POSIX_FADV_WILLNEED);
    1664           0 :                         r = 0;
    1665             :                 }
    1666             : 
    1667         701 :                 display_progress(block);
    1668             : 
    1669         701 :                 if (fsck_abort)
    1670           0 :                         return FSCK_OK;
    1671             : 
    1672         701 :                 if (skip_this_pass) {
    1673           0 :                         printf( _("Skipping pass 1 is not a good idea.\n"));
    1674           0 :                         skip_this_pass = 0;
    1675           0 :                         fflush(stdout);
    1676             :                 }
    1677         701 :                 if (fsck_system_inode(sdp, block)) {
    1678         511 :                         log_debug(_("Already processed system inode %"PRIu64" (0x%"PRIx64")\n"),
    1679             :                                   block, block);
    1680         511 :                         continue;
    1681             :                 }
    1682             : 
    1683         190 :                 bh = lgfs2_bread(sdp, block);
    1684             : 
    1685         190 :                 is_inode = 0;
    1686         190 :                 if (lgfs2_check_meta(bh->b_data, GFS2_METATYPE_DI) == 0)
    1687         189 :                         is_inode = 1;
    1688             : 
    1689         190 :                 q = block_type(bl, block);
    1690         190 :                 if (q != GFS2_BLKST_FREE) {
    1691           0 :                         log_err(_("Found a duplicate inode block at %"PRIu64" (0x%"PRIx64") "
    1692             :                                   "previously marked as a %s\n"),
    1693             :                                  block, block, block_type_string(q));
    1694           0 :                         ip = fsck_inode_get(sdp, rgd, bh);
    1695           0 :                         if (is_inode && ip->i_num.in_addr == block)
    1696           0 :                                 add_duplicate_ref(cx, ip, block, REF_IS_INODE, 0,
    1697             :                                                   INODE_VALID);
    1698             :                         else
    1699           0 :                                 log_info(_("dinum.no_addr is wrong, so I "
    1700             :                                            "assume the bitmap is just "
    1701             :                                            "wrong.\n"));
    1702           0 :                         fsck_inode_put(&ip);
    1703           0 :                         lgfs2_brelse(bh);
    1704           0 :                         continue;
    1705             :                 }
    1706             : 
    1707         190 :                 if (!is_inode) {
    1708           1 :                         log_err(_("Found invalid inode at block %"PRIu64" (0x%"PRIx64")\n"),
    1709             :                                 block, block);
    1710           1 :                         check_n_fix_bitmap(cx, rgd, block, 0, GFS2_BLKST_FREE);
    1711         189 :                 } else if (handle_di(cx, rgd, bh) < 0) {
    1712           0 :                         stack;
    1713           0 :                         lgfs2_brelse(bh);
    1714           0 :                         return FSCK_ERROR;
    1715             :                 }
    1716             :                 /* Ignore everything else - they should be hit by the
    1717             :                    handle_di step.  Don't check NONE either, because
    1718             :                    check_meta passes everything if GFS2_METATYPE_NONE
    1719             :                    is specified.  Hopefully, other metadata types such
    1720             :                    as indirect blocks will be handled when the inode
    1721             :                    itself is processed, and if it's not, it should be
    1722             :                    caught in pass5. */
    1723         190 :                 lgfs2_brelse(bh);
    1724             :         }
    1725             : 
    1726         177 :         return 0;
    1727             : }
    1728             : 
    1729        4359 : static int pass1_process_rgrp(struct fsck_cx *cx, struct lgfs2_rgrp_tree *rgd)
    1730             : {
    1731             :         unsigned k, n;
    1732        4359 :         uint64_t *ibuf = malloc(cx->sdp->sd_bsize * GFS2_NBBY * sizeof(uint64_t));
    1733        4359 :         int ret = 0;
    1734             : 
    1735        4359 :         if (ibuf == NULL)
    1736           0 :                 return FSCK_ERROR;
    1737             : 
    1738      136822 :         for (k = 0; k < rgd->rt_length; k++) {
    1739      132463 :                 n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_DINODE);
    1740             : 
    1741      132463 :                 if (n) {
    1742         177 :                         ret = pass1_process_bitmap(cx, rgd, ibuf, n);
    1743         177 :                         if (ret)
    1744           0 :                                 goto out;
    1745             :                 }
    1746             : 
    1747      132463 :                 if (fsck_abort)
    1748           0 :                         goto out;
    1749             :         }
    1750             : 
    1751        4359 : out:
    1752        4359 :         free(ibuf);
    1753        4359 :         return ret;
    1754             : }
    1755             : 
    1756          56 : static int blockmap_create(struct bmap *bmap, uint64_t size)
    1757             : {
    1758          56 :         bmap->size = size;
    1759             : 
    1760             :         /* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
    1761             :          * must be 1-based */
    1762          56 :         bmap->mapsize = BLOCKMAP_SIZE2(size) + 1;
    1763             : 
    1764          56 :         if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
    1765           0 :                 return -ENOMEM;
    1766          56 :         return 0;
    1767             : }
    1768             : 
    1769             : 
    1770         112 : static int link1_create(struct bmap *bmap, uint64_t size)
    1771             : {
    1772         112 :         bmap->size = size;
    1773             : 
    1774             :         /* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
    1775             :          * must be 1-based */
    1776         112 :         bmap->mapsize = BLOCKMAP_SIZE1(size) + 1;
    1777             : 
    1778         112 :         if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
    1779           0 :                 return -ENOMEM;
    1780         112 :         return 0;
    1781             : }
    1782             : 
    1783          56 : static struct bmap *bmap_create(struct lgfs2_sbd *sdp, uint64_t size,
    1784             :                                           uint64_t *addl_mem_needed)
    1785             : {
    1786             :         struct bmap *il;
    1787             : 
    1788          56 :         *addl_mem_needed = 0L;
    1789          56 :         il = calloc(1, sizeof(*il));
    1790          56 :         if (!il)
    1791           0 :                 return NULL;
    1792             : 
    1793          56 :         if (blockmap_create(il, size)) {
    1794           0 :                 *addl_mem_needed = il->mapsize;
    1795           0 :                 free(il);
    1796           0 :                 il = NULL;
    1797             :         }
    1798          56 :         return il;
    1799             : }
    1800             : 
    1801          56 : static void blockmap_destroy(struct bmap *bmap)
    1802             : {
    1803          56 :         if (bmap->map)
    1804          56 :                 free(bmap->map);
    1805          56 :         bmap->size = 0;
    1806          56 :         bmap->mapsize = 0;
    1807          56 : }
    1808             : 
    1809          56 : static void *bmap_destroy(struct lgfs2_sbd *sdp, struct bmap *il)
    1810             : {
    1811          56 :         if (il) {
    1812          56 :                 blockmap_destroy(il);
    1813          56 :                 free(il);
    1814          56 :                 il = NULL;
    1815             :         }
    1816          56 :         return il;
    1817             : }
    1818             : 
    1819           0 : static void enomem(uint64_t addl_mem_needed)
    1820             : {
    1821           0 :         log_crit( _("This system doesn't have enough memory and swap space to fsck this file system.\n"));
    1822           0 :         log_crit( _("Additional memory needed is approximately: %"PRIu64"MB\n"),
    1823             :                  (uint64_t)(addl_mem_needed / 1048576ULL));
    1824           0 :         log_crit( _("Please increase your swap space by that amount and run fsck.gfs2 again.\n"));
    1825           0 : }
    1826             : 
    1827             : /**
    1828             :  * pass1 - walk through inodes and check inode state
    1829             :  *
    1830             :  * this walk can be done using root inode and depth first search,
    1831             :  * watching for repeat inode numbers
    1832             :  *
    1833             :  * format & type
    1834             :  * link count
    1835             :  * duplicate blocks
    1836             :  * bad blocks
    1837             :  * inodes size
    1838             :  * dir info
    1839             :  */
    1840          56 : int pass1(struct fsck_cx *cx)
    1841             : {
    1842          56 :         struct lgfs2_sbd *sdp = cx->sdp;
    1843          56 :         struct osi_node *n, *next = NULL;
    1844             :         struct lgfs2_rgrp_tree *rgd;
    1845             :         uint64_t i;
    1846          56 :         uint64_t rg_count = 0;
    1847             :         struct timeval timer;
    1848          56 :         int ret = FSCK_OK;
    1849             :         uint64_t addl_mem_needed;
    1850             : 
    1851          56 :         bl = bmap_create(sdp, last_fs_block+1, &addl_mem_needed);
    1852          56 :         if (!bl) {
    1853           0 :                 enomem(addl_mem_needed);
    1854           0 :                 return FSCK_ERROR;
    1855             :         }
    1856          56 :         addl_mem_needed = link1_create(&nlink1map, last_fs_block+1);
    1857          56 :         if (addl_mem_needed) {
    1858           0 :                 enomem(addl_mem_needed);
    1859           0 :                 bmap_destroy(sdp, bl);
    1860           0 :                 return FSCK_ERROR;
    1861             :         }
    1862          56 :         addl_mem_needed = link1_create(&clink1map, last_fs_block+1);
    1863          56 :         if (addl_mem_needed) {
    1864           0 :                 enomem(addl_mem_needed);
    1865           0 :                 link1_destroy(&nlink1map);
    1866           0 :                 bmap_destroy(sdp, bl);
    1867           0 :                 return FSCK_ERROR;
    1868             :         }
    1869             : 
    1870             :         /* FIXME: In the gfs fsck, we had to mark things like the
    1871             :          * journals and indices and such as 'other_meta' - in gfs2,
    1872             :          * the journals are files and are found in the normal file
    1873             :          * sweep - is there any metadata we need to mark here before
    1874             :          * the sweeps start that we won't find otherwise? */
    1875             : 
    1876             :         /* Make sure the system inodes are okay & represented in the bitmap. */
    1877          56 :         check_system_inodes(cx);
    1878             : 
    1879             :         /* So, do we do a depth first search starting at the root
    1880             :          * inode, or use the rg bitmaps, or just read every fs block
    1881             :          * to find the inodes?  If we use the depth first search, why
    1882             :          * have pass3 at all - if we use the rg bitmaps, pass5 is at
    1883             :          * least partially invalidated - if we read every fs block,
    1884             :          * things will probably be intolerably slow.  The current fsck
    1885             :          * uses the rg bitmaps, so maybe that's the best way to start
    1886             :          * things - we can change the method later if necessary.
    1887             :          */
    1888        4415 :         for (n = osi_first(&sdp->rgtree); n; n = next, rg_count++) {
    1889        4359 :                 if (fsck_abort) {
    1890           0 :                         ret = FSCK_CANCELED;
    1891           0 :                         goto out;
    1892             :                 }
    1893        4359 :                 next = osi_next(n);
    1894        4359 :                 log_debug("Checking metadata in resource group #%"PRIu64"\n", rg_count);
    1895        4359 :                 rgd = (struct lgfs2_rgrp_tree *)n;
    1896      136822 :                 for (i = 0; i < rgd->rt_length; i++) {
    1897      132463 :                         log_debug("rgrp block %"PRIu64" (0x%"PRIx64") is now marked as 'rgrp data'\n",
    1898             :                                    rgd->rt_addr + i, rgd->rt_addr + i);
    1899      132463 :                         if (blockmap_set(bl, rgd->rt_addr + i, GFS2_BLKST_USED)) {
    1900           0 :                                 stack;
    1901           0 :                                 ret = FSCK_ERROR;
    1902           0 :                                 goto out;
    1903             :                         }
    1904             :                         /* rgrps and bitmaps don't have bits to represent
    1905             :                            their blocks, so don't do this:
    1906             :                         check_n_fix_bitmap(sdp, rgd, rgd->ri.ri_num.in_addr + i, 0,
    1907             :                         gfs2_meta_rgrp);*/
    1908             :                 }
    1909             : 
    1910        4359 :                 ret = pass1_process_rgrp(cx, rgd);
    1911        4359 :                 if (ret)
    1912           0 :                         goto out;
    1913             :         }
    1914          56 :         log_notice(_("Reconciling bitmaps.\n"));
    1915          56 :         gettimeofday(&timer, NULL);
    1916          56 :         pass5(cx, bl);
    1917          56 :         print_pass_duration("reconcile_bitmaps", &timer);
    1918          56 : out:
    1919          56 :         if (bl)
    1920          56 :                 bmap_destroy(sdp, bl);
    1921          56 :         return ret;
    1922             : }
    1923             : 
    1924             : static struct metawalk_fxns pass1_fxns = {
    1925             :         .private = NULL,
    1926             :         .check_leaf = p1_check_leaf,
    1927             :         .check_metalist = p1_check_metalist,
    1928             :         .check_data = p1_check_data,
    1929             :         .check_eattr_indir = p1_check_eattr_indir,
    1930             :         .check_eattr_leaf = p1_check_eattr_leaf,
    1931             :         .check_dentry = NULL,
    1932             :         .check_eattr_entry = p1_check_eattr_entry,
    1933             :         .check_eattr_extentry = p1_check_extended_leaf_eattr,
    1934             :         .big_file_msg = big_file_comfort,
    1935             :         .repair_leaf = p1_repair_leaf,
    1936             :         .undo_check_meta = p1_undo_check_metalist,
    1937             :         .undo_check_data = p1_undo_check_data,
    1938             :         .delete_block = p1_delete_block,
    1939             : };

Generated by: LCOV version 1.14