LCOV - code coverage report
Current view: top level - fsck - pass1.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 296 886 33.4 %
Date: 2023-10-25 12:04:14 Functions: 27 58 46.6 %

          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     2099007 : 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     2099007 :         if (!bmap)
      46           0 :                 return 0;
      47     2099007 :         if (bblock > bmap->size)
      48           0 :                 return -1;
      49             : 
      50     2099007 :         byte = bmap->map + BLOCKMAP_SIZE2(bblock);
      51     2099007 :         b = BLOCKMAP_BYTE_OFFSET2(bblock);
      52     2099007 :         *byte &= ~(BLOCKMAP_MASK2 << b);
      53     2099007 :         *byte |= (mark & BLOCKMAP_MASK2) << b;
      54     2099007 :         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     1966544 : 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     1966544 :         int error = _fsck_bitmap_set(cx, ip, bblock, btype, mark, error_on_dinode,
      66             :                                      caller, fline);
      67     1966544 :         if (error)
      68           0 :                 return error;
      69             : 
      70     1966544 :         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        1036 : 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        1036 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     174             :         struct lgfs2_dirent d;
     175             :         char tmp_name[GFS2_FNAMESIZE];
     176             :         uint64_t block;
     177             : 
     178        1036 :         lgfs2_dirent_in(&d, dent);
     179        1036 :         block = d.dr_inum.in_addr;
     180             :         /* Start of checks */
     181        1036 :         memset(tmp_name, 0, sizeof(tmp_name));
     182        1036 :         if (d.dr_name_len < sizeof(tmp_name))
     183        1036 :                 strncpy(tmp_name, filename, d.dr_name_len);
     184             :         else
     185           0 :                 strncpy(tmp_name, filename, sizeof(tmp_name) - 1);
     186        1036 :         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        1036 :         if (fsck_system_inode(sdp, block))
     197         846 :                 fsck_blockmap_set(cx, ip, block, _("system file"),
     198             :                                   GFS2_BLKST_DINODE);
     199             :         else
     200         190 :                 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        1036 :         *count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
     205        1036 :         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        7328 : 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        7328 :         struct block_count *bc = (struct block_count *)private;
     245        7328 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     246        7328 :         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        7328 :         *bh = NULL;
     253             : 
     254        7328 :         *was_duplicate = 0;
     255        7328 :         *is_valid = 0;
     256        7328 :         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        7328 :         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        7328 :                 iblk_type = GFS2_METATYPE_IN;
     274        7328 :                 blktypedesc = _("a journaled data block");
     275             :         }
     276        7328 :         q = block_type(bl, block);
     277        7328 :         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        7328 :         nbh = lgfs2_bread(ip->i_sbd, block);
     286             : 
     287        7328 :         *is_valid = (lgfs2_check_meta(nbh->b_data, iblk_type) == 0);
     288             : 
     289        7328 :         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        7328 :         bc->indir_count++;
     307        7328 :         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        7328 :                 *bh = nbh;
     313        7328 :                 fsck_blockmap_set(cx, ip, block, _("indirect"), GFS2_BLKST_USED);
     314             :         }
     315             : 
     316        7328 :         if (*is_valid)
     317        7328 :                 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     1957548 : 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     1957548 :         error = fsck_blkmap_set_noino(cx, ip, block, "data", GFS2_BLKST_USED);
     408     1957548 :         if (!error)
     409     1957548 :                 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     1957548 : 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     1957548 :         struct block_count *bc = (struct block_count *) private;
     441             : 
     442     1957548 :         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     1957548 :         bc->data_count++; /* keep the count sane anyway */
     458     1957548 :         q = block_type(bl, block);
     459     1957548 :         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     1957548 :         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     1964885 : 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     1964885 :         long *bad_pointers = (long *)private;
     937             :         int q;
     938             : 
     939     1964885 :         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     1964885 :         q = block_type(bl, block);
     951     1964885 :         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     1964885 :         return META_IS_GOOD;
     966             : }
     967             : 
     968        7328 : 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        7328 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     972        7328 :         uint64_t block = iptr_block(iptr);
     973             : 
     974        7328 :         *is_valid = 1;
     975        7328 :         *was_duplicate = 0;
     976        7328 :         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     1957548 : 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     1957548 :         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         700 : static int set_ip_blockmap(struct fsck_cx *cx, struct lgfs2_inode *ip)
    1029             : {
    1030         700 :         uint64_t block = ip->i_bh->b_blocknr;
    1031             :         struct lgfs2_inum no;
    1032             :         uint32_t mode;
    1033             :         const char *ty;
    1034             : 
    1035         700 :         mode = ip->i_mode & S_IFMT;
    1036             : 
    1037         700 :         switch (mode) {
    1038         224 :         case S_IFDIR:
    1039         224 :                 ty = "directory";
    1040         224 :                 break;
    1041         476 :         case S_IFREG:
    1042         476 :                 ty = "file";
    1043         476 :                 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         700 :         no = ip->i_num;
    1063         700 :         if (fsck_blockmap_set(cx, ip, block, ty, GFS2_BLKST_DINODE) ||
    1064         224 :             (mode == S_IFDIR && !dirtree_insert(cx, no))) {
    1065           0 :                 stack;
    1066           0 :                 return -EPERM;
    1067             :         }
    1068         700 :         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        1407 : static int pass1_check_metatree(struct fsck_cx *cx, struct lgfs2_inode *ip,
    1150             :                                 struct metawalk_fxns *pass)
    1151             : {
    1152             :         int error;
    1153             : 
    1154        1407 :         error = check_metatree(cx, ip, pass);
    1155        1407 :         if (error)
    1156           0 :                 blockmap_set(bl, ip->i_num.in_addr, GFS2_BLKST_FREE);
    1157        1407 :         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         700 : static int handle_ip(struct fsck_cx *cx, struct lgfs2_inode *ip)
    1195             : {
    1196             :         int error;
    1197         700 :         struct block_count bc = {0};
    1198             :         long bad_pointers;
    1199         700 :         uint64_t lf_blks = 0;
    1200             : 
    1201         700 :         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         700 :         rangecheck_fxns.private = &bad_pointers;
    1208         700 :         error = pass1_check_metatree(cx, ip, &rangecheck_fxns);
    1209         700 :         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         700 :         error = set_ip_blockmap(cx, ip);
    1217         700 :         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         700 :         } else if (error)
    1227           0 :                 goto bad_dinode;
    1228             : 
    1229         700 :         if (set_di_nlink(cx, ip))
    1230           0 :                 goto bad_dinode;
    1231             : 
    1232         700 :         if (lf_dip)
    1233           0 :                 lf_blks = lf_dip->i_blocks;
    1234             : 
    1235         700 :         pass1_fxns.private = &bc;
    1236         700 :         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         700 :         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         700 :         if (fsck_abort)
    1247           0 :                 return 0;
    1248             : 
    1249         700 :         if (!error) {
    1250         700 :                 error = check_inode_eattr(cx, ip, &pass1_fxns);
    1251             : 
    1252         700 :                 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         700 :         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         700 :         return 0;
    1286           0 : bad_dinode:
    1287           0 :         stack;
    1288           0 :         return -1;
    1289             : }
    1290             : 
    1291         700 : static void check_i_goal(struct fsck_cx *cx, struct lgfs2_inode *ip)
    1292             : {
    1293         700 :         if (ip->i_flags & GFS2_DIF_SYSTEM)
    1294         644 :                 return;
    1295             : 
    1296          56 :         if (ip->i_goal_meta <= LGFS2_SB_ADDR(cx->sdp) ||
    1297          55 :             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         189 : static int handle_di(struct fsck_cx *cx, struct lgfs2_rgrp_tree *rgd,
    1317             :                      struct lgfs2_buffer_head *bh)
    1318             : {
    1319         189 :         int error = 0;
    1320         189 :         uint64_t block = bh->b_blocknr;
    1321             :         struct lgfs2_inode *ip;
    1322             : 
    1323         189 :         ip = fsck_inode_get(cx->sdp, rgd, bh);
    1324             : 
    1325         189 :         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         189 :         check_i_goal(cx, ip);
    1338         189 :         error = handle_ip(cx, ip);
    1339         189 :         fsck_inode_put(&ip);
    1340         189 :         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         511 : 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         511 :         uint64_t iblock = 0;
    1354         511 :         struct dir_status ds = {0};
    1355         511 :         int error, err = 0;
    1356             : 
    1357         511 :         log_info( _("Checking system inode '%s'\n"), filename);
    1358         511 :         if (*sysinode) {
    1359             :                 /* Read in the system inode, look at its dentries, and start
    1360             :                  * reading through them */
    1361         510 :                 iblock = (*sysinode)->i_num.in_addr;
    1362         510 :                 log_info(_("System inode for '%s' is located at block %"PRIu64" (0x%"PRIx64")\n"),
    1363             :                          filename, iblock, iblock);
    1364         510 :                 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         511 :         if (*sysinode) {
    1374         510 :                 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         510 :                 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         510 :                 if (needs_sysbit &&
    1392         454 :                     !((*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         511 :         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         511 :         if (is_dir(*sysinode)) {
    1446         224 :                 struct block_count bc = {0};
    1447             : 
    1448         224 :                 sysdir_fxns.private = &bc;
    1449         224 :                 if ((*sysinode)->i_flags & GFS2_DIF_EXHASH)
    1450           7 :                         pass1_check_metatree(cx, *sysinode, &sysdir_fxns);
    1451             :                 else {
    1452         217 :                         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         217 :                         if (err)
    1458           0 :                                 log_err(_("Error found in %s while checking "
    1459             :                                           "directory entries.\n"), filename);
    1460             :                 }
    1461             :         }
    1462         511 :         check_i_goal(cx, *sysinode);
    1463         511 :         error = handle_ip(cx, *sysinode);
    1464         511 :         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          56 : static int check_system_inodes(struct fsck_cx *cx)
    1583             : {
    1584          56 :         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          56 :         fsck_blockmap_set(cx, sdp->master_dir, sdp->master_dir->i_num.in_addr,
    1591             :                           "master", GFS2_BLKST_DINODE);
    1592          56 :         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          56 :         fsck_blockmap_set(cx, sdp->md.rooti, sdp->md.rooti->i_num.in_addr,
    1600             :                           "root", GFS2_BLKST_DINODE);
    1601          56 :         if (check_system_inode(cx, &sdp->md.rooti, "root", build_root, 1,
    1602             :                                NULL, 0)) {
    1603           0 :                 stack;
    1604           0 :                 return -1;
    1605             :         }
    1606          56 :         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          56 :         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          56 :         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          56 :         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          56 :         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          56 :         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          56 :         journal_count = sdp->md.journals;
    1639         119 :         for (sdp->md.journals = 0; sdp->md.journals < journal_count;
    1640          63 :              sdp->md.journals++) {
    1641             :                 char jname[16];
    1642             : 
    1643          63 :                 sprintf(jname, "journal%d", sdp->md.journals);
    1644          63 :                 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          56 :         return 0;
    1653             : }
    1654             : 
    1655         176 : 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         176 :         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         176 :         unsigned rawin = 50;
    1665         176 :         unsigned ralen = 100 * sdp->sd_bsize;
    1666         176 :         unsigned r = 0;
    1667             : 
    1668         877 :         for (i = 0; i < n; i++) {
    1669             :                 int is_inode;
    1670             : 
    1671         701 :                 block = ibuf[i];
    1672             : 
    1673         701 :                 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         701 :                 display_progress(block);
    1679             : 
    1680         701 :                 if (fsck_abort)
    1681           0 :                         return FSCK_OK;
    1682             : 
    1683         701 :                 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         701 :                 if (fsck_system_inode(sdp, block)) {
    1689         511 :                         log_debug(_("Already processed system inode %"PRIu64" (0x%"PRIx64")\n"),
    1690             :                                   block, block);
    1691         511 :                         continue;
    1692             :                 }
    1693             : 
    1694         190 :                 bh = lgfs2_bread(sdp, block);
    1695             : 
    1696         190 :                 is_inode = 0;
    1697         190 :                 if (lgfs2_check_meta(bh->b_data, GFS2_METATYPE_DI) == 0)
    1698         189 :                         is_inode = 1;
    1699             : 
    1700         190 :                 q = block_type(bl, block);
    1701         190 :                 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         190 :                 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         189 :                 } 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         190 :                 lgfs2_brelse(bh);
    1735             :         }
    1736             : 
    1737         176 :         return 0;
    1738             : }
    1739             : 
    1740        4359 : static int pass1_process_rgrp(struct fsck_cx *cx, struct lgfs2_rgrp_tree *rgd)
    1741             : {
    1742             :         unsigned k, n;
    1743        4359 :         uint64_t *ibuf = malloc(cx->sdp->sd_bsize * GFS2_NBBY * sizeof(uint64_t));
    1744        4359 :         int ret = 0;
    1745             : 
    1746        4359 :         if (ibuf == NULL)
    1747           0 :                 return FSCK_ERROR;
    1748             : 
    1749      136822 :         for (k = 0; k < rgd->rt_length; k++) {
    1750      132463 :                 n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_DINODE);
    1751             : 
    1752      132463 :                 if (n) {
    1753         176 :                         ret = pass1_process_bitmap(cx, rgd, ibuf, n);
    1754         176 :                         if (ret)
    1755           0 :                                 goto out;
    1756             :                 }
    1757             : 
    1758      132463 :                 if (fsck_abort)
    1759           0 :                         goto out;
    1760             :         }
    1761             : 
    1762        4359 : out:
    1763        4359 :         free(ibuf);
    1764        4359 :         return ret;
    1765             : }
    1766             : 
    1767          56 : static int blockmap_create(struct bmap *bmap, uint64_t size)
    1768             : {
    1769          56 :         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          56 :         bmap->mapsize = BLOCKMAP_SIZE2(size) + 1;
    1774             : 
    1775          56 :         if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
    1776           0 :                 return -ENOMEM;
    1777          56 :         return 0;
    1778             : }
    1779             : 
    1780             : 
    1781         112 : static int link1_create(struct bmap *bmap, uint64_t size)
    1782             : {
    1783         112 :         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         112 :         bmap->mapsize = BLOCKMAP_SIZE1(size) + 1;
    1788             : 
    1789         112 :         if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
    1790           0 :                 return -ENOMEM;
    1791         112 :         return 0;
    1792             : }
    1793             : 
    1794          56 : 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          56 :         *addl_mem_needed = 0L;
    1800          56 :         il = calloc(1, sizeof(*il));
    1801          56 :         if (!il)
    1802           0 :                 return NULL;
    1803             : 
    1804          56 :         if (blockmap_create(il, size)) {
    1805           0 :                 *addl_mem_needed = il->mapsize;
    1806           0 :                 free(il);
    1807           0 :                 il = NULL;
    1808             :         }
    1809          56 :         return il;
    1810             : }
    1811             : 
    1812          56 : static void blockmap_destroy(struct bmap *bmap)
    1813             : {
    1814          56 :         if (bmap->map)
    1815          56 :                 free(bmap->map);
    1816          56 :         bmap->size = 0;
    1817          56 :         bmap->mapsize = 0;
    1818          56 : }
    1819             : 
    1820          56 : static void *bmap_destroy(struct lgfs2_sbd *sdp, struct bmap *il)
    1821             : {
    1822          56 :         if (il) {
    1823          56 :                 blockmap_destroy(il);
    1824          56 :                 free(il);
    1825          56 :                 il = NULL;
    1826             :         }
    1827          56 :         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          56 : int pass1(struct fsck_cx *cx)
    1852             : {
    1853          56 :         struct lgfs2_sbd *sdp = cx->sdp;
    1854          56 :         struct osi_node *n, *next = NULL;
    1855             :         struct lgfs2_rgrp_tree *rgd;
    1856             :         uint64_t i;
    1857          56 :         uint64_t rg_count = 0;
    1858             :         struct timeval timer;
    1859          56 :         int ret = FSCK_OK;
    1860             :         uint64_t addl_mem_needed;
    1861             : 
    1862          56 :         bl = bmap_create(sdp, last_fs_block+1, &addl_mem_needed);
    1863          56 :         if (!bl) {
    1864           0 :                 enomem(addl_mem_needed);
    1865           0 :                 return FSCK_ERROR;
    1866             :         }
    1867          56 :         addl_mem_needed = link1_create(&nlink1map, last_fs_block+1);
    1868          56 :         if (addl_mem_needed) {
    1869           0 :                 enomem(addl_mem_needed);
    1870           0 :                 bmap_destroy(sdp, bl);
    1871           0 :                 return FSCK_ERROR;
    1872             :         }
    1873          56 :         addl_mem_needed = link1_create(&clink1map, last_fs_block+1);
    1874          56 :         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          56 :         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        4415 :         for (n = osi_first(&sdp->rgtree); n; n = next, rg_count++) {
    1900        4359 :                 if (fsck_abort) {
    1901           0 :                         ret = FSCK_CANCELED;
    1902           0 :                         goto out;
    1903             :                 }
    1904        4359 :                 next = osi_next(n);
    1905        4359 :                 log_debug("Checking metadata in resource group #%"PRIu64"\n", rg_count);
    1906        4359 :                 rgd = (struct lgfs2_rgrp_tree *)n;
    1907      136822 :                 for (i = 0; i < rgd->rt_length; i++) {
    1908      132463 :                         log_debug("rgrp block %"PRIu64" (0x%"PRIx64") is now marked as 'rgrp data'\n",
    1909             :                                    rgd->rt_addr + i, rgd->rt_addr + i);
    1910      132463 :                         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        4359 :                 ret = pass1_process_rgrp(cx, rgd);
    1922        4359 :                 if (ret)
    1923           0 :                         goto out;
    1924             :         }
    1925          56 :         log_notice(_("Reconciling bitmaps.\n"));
    1926          56 :         gettimeofday(&timer, NULL);
    1927          56 :         pass5(cx, bl);
    1928          56 :         print_pass_duration("reconcile_bitmaps", &timer);
    1929          56 : out:
    1930          56 :         if (bl)
    1931          56 :                 bmap_destroy(sdp, bl);
    1932          56 :         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 1.14