LCOV - code coverage report
Current view: top level - fsck - pass1.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 33.4 % 886 296
Test Date: 2024-03-07 16:24:06 Functions: 46.6 % 58 27

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

Generated by: LCOV version 2.0-1