LCOV - code coverage report
Current view: top level - fsck - pass1b.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 1.9 % 362 7
Test Date: 2024-03-07 16:24:06 Functions: 4.8 % 21 1

            Line data    Source code
       1              : #include "clusterautoconfig.h"
       2              : 
       3              : #include <inttypes.h>
       4              : #include <stdlib.h>
       5              : #include <string.h>
       6              : #include <unistd.h>
       7              : #include <libintl.h>
       8              : #include <sys/stat.h>
       9              : #define _(String) gettext(String)
      10              : 
      11              : #include <logging.h>
      12              : #include "libgfs2.h"
      13              : #include "link.h"
      14              : #include "fsck.h"
      15              : #include "osi_list.h"
      16              : #include "util.h"
      17              : #include "metawalk.h"
      18              : #include "inode_hash.h"
      19              : #include "afterpass1_common.h"
      20              : 
      21              : struct fxn_info {
      22              :         uint64_t block;
      23              :         int found;
      24              :         int ea_only;    /* The only dups were found in EAs */
      25              : };
      26              : 
      27              : struct dup_handler {
      28              :         struct duptree *dt;
      29              :         int ref_inode_count;
      30              :         int ref_count;
      31              : };
      32              : 
      33              : struct clone_target {
      34              :         uint64_t dup_block;
      35              :         int first;
      36              : };
      37              : 
      38              : struct meta_blk_ref {
      39              :         uint64_t block; /* block to locate */
      40              :         uint64_t metablock; /* returned metadata block addr containing ref */
      41              :         int off; /* offset to the reference within the buffer */
      42              : };
      43              : 
      44              : static int clone_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
      45              :                       uint64_t block, void *private,
      46              :                       struct lgfs2_buffer_head *bh, __be64 *ptr);
      47              : 
      48            0 : static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
      49              : {
      50              :         char reftypestring[32];
      51              :         struct inode_with_dups *id;
      52              : 
      53            0 :         id = osi_list_entry(tmp, struct inode_with_dups, list);
      54            0 :         if (id->dup_count == 1)
      55            0 :                 sprintf(reftypestring, "as %s", reftypes[get_ref_type(id)]);
      56              :         else
      57            0 :                 sprintf(reftypestring, "%d/%d/%d/%d",
      58              :                         id->reftypecount[REF_IS_INODE],
      59              :                         id->reftypecount[REF_AS_DATA],
      60              :                         id->reftypecount[REF_AS_META],
      61              :                         id->reftypecount[REF_AS_EA]);
      62            0 :         if (inval)
      63            0 :                 log_warn( _("Invalid "));
      64            0 :         log_warn(_("Inode %s (%"PRIu64"/0x%"PRIx64") has %d reference(s) to block %"PRIu64" (0x%"PRIx64") (%s)\n"),
      65              :                  id->name, id->block_no, id->block_no, id->dup_count, dt->block, dt->block,
      66              :                  reftypestring);
      67            0 : }
      68              : 
      69            0 : static int findref_meta(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
      70              :                         int *is_valid, int *was_duplicate, void *private)
      71              : {
      72            0 :         *is_valid = 1;
      73            0 :         *was_duplicate = 0;
      74            0 :         return META_IS_GOOD;
      75              : }
      76              : 
      77            0 : static int findref_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
      78              :                         uint64_t block, void *private,
      79              :                         struct lgfs2_buffer_head *bh, __be64 *ptr)
      80              : {
      81            0 :         struct meta_blk_ref *mbr = (struct meta_blk_ref *)private;
      82              : 
      83            0 :         if (block == mbr->block) {
      84            0 :                 mbr->metablock = bh->b_blocknr;
      85            0 :                 mbr->off = (ptr - (__be64 *)bh->b_data);
      86            0 :                 log_debug("Duplicate data reference located on metadata block 0x%"PRIx64", offset 0x%x\n",
      87              :                           mbr->metablock, mbr->off);
      88              :         }
      89            0 :         return META_IS_GOOD;
      90              : }
      91              : 
      92            0 : static void clone_data_block(struct fsck_cx *cx, struct duptree *dt,
      93              :                              struct inode_with_dups *id)
      94              : {
      95            0 :         struct meta_blk_ref metaref = { .block = dt->block, };
      96            0 :         struct metawalk_fxns find1ref_fxns = {
      97              :                 .private = &metaref,
      98              :                 .check_metalist = findref_meta,
      99              :                 .check_data = findref_data,
     100              :         };
     101            0 :         struct clone_target clone = {.dup_block = dt->block,};
     102              :         struct lgfs2_inode *ip;
     103              :         struct lgfs2_buffer_head *bh;
     104              :         __be64 *ptr;
     105              : 
     106            0 :         if (!(query(cx, _("Okay to clone data block %"PRIu64" (0x%"PRIx64") for inode %"PRIu64" (0x%"PRIx64")? (y/n) "),
     107              :                     dt->block, dt->block, id->block_no, id->block_no))) {
     108            0 :                 log_warn(_("The duplicate reference was not cloned.\n"));
     109            0 :                 return;
     110              :         }
     111            0 :         ip = fsck_load_inode(cx->sdp, id->block_no);
     112            0 :         check_metatree(cx, ip, &find1ref_fxns);
     113            0 :         if (metaref.metablock == 0) {
     114            0 :                 log_err(_("Unable to clone data block.\n"));
     115              :         } else {
     116            0 :                 if (metaref.metablock != id->block_no)
     117            0 :                         bh = lgfs2_bread(cx->sdp, metaref.metablock);
     118              :                 else
     119            0 :                         bh = ip->i_bh;
     120            0 :                 ptr = (__be64 *)bh->b_data + metaref.off;
     121            0 :                 clone_data(cx, ip, 0, dt->block, &clone, bh, ptr);
     122            0 :                 if (metaref.metablock != id->block_no)
     123            0 :                         lgfs2_brelse(bh);
     124              :                 else
     125            0 :                         lgfs2_bmodified(ip->i_bh);
     126              :         }
     127            0 :         fsck_inode_put(&ip); /* out, lgfs2_brelse, free */
     128              : }
     129              : 
     130              : /* revise_dup_handler - get current information about a duplicate reference
     131              :  *
     132              :  * Function resolve_dup_references can delete dinodes that reference blocks
     133              :  * which may have duplicate references. Therefore, the duplicate tree is
     134              :  * constantly being changed. This function revises the duplicate handler so
     135              :  * that it accurately matches what's in the duplicate tree regarding this block
     136              :  */
     137            0 : static void revise_dup_handler(struct fsck_cx *cx, uint64_t dup_blk, struct dup_handler *dh)
     138              : {
     139              :         osi_list_t *tmp;
     140              :         struct duptree *dt;
     141              :         struct inode_with_dups *id;
     142              : 
     143            0 :         dh->ref_inode_count = 0;
     144            0 :         dh->ref_count = 0;
     145            0 :         dh->dt = NULL;
     146              : 
     147            0 :         dt = dupfind(cx, dup_blk);
     148            0 :         if (!dt)
     149            0 :                 return;
     150              : 
     151            0 :         dh->dt = dt;
     152              :         /* Count the duplicate references, both valid and invalid */
     153            0 :         osi_list_foreach(tmp, &dt->ref_invinode_list) {
     154            0 :                 id = osi_list_entry(tmp, struct inode_with_dups, list);
     155            0 :                 dh->ref_inode_count++;
     156            0 :                 dh->ref_count += id->dup_count;
     157              :         }
     158            0 :         osi_list_foreach(tmp, &dt->ref_inode_list) {
     159            0 :                 id = osi_list_entry(tmp, struct inode_with_dups, list);
     160            0 :                 dh->ref_inode_count++;
     161            0 :                 dh->ref_count += id->dup_count;
     162              :         }
     163              : }
     164              : 
     165              : /*
     166              :  * resolve_dup_references - resolve all but the last dinode that has a
     167              :  *                          duplicate reference to a given block.
     168              :  *
     169              :  * @sdp - pointer to the superblock structure
     170              :  * @dt - pointer to the duplicate reference rbtree to use
     171              :  * @ref_list - list of duplicate references to be resolved (invalid or valid)
     172              :  * @dh - duplicate handler
     173              :  * inval - The references on this ref_list are invalid.  We prefer to delete
     174              :  *         these first before resorting to deleting valid dinodes.
     175              :  * acceptable_ref - Delete dinodes that reference the given block as anything
     176              :  *                  _but_ this type.  Try to save references as this type.
     177              :  */
     178            0 : static void resolve_dup_references(struct fsck_cx *cx, struct duptree *dt,
     179              :                                    osi_list_t *ref_list,
     180              :                                    struct dup_handler *dh,
     181              :                                    int inval, int acceptable_ref)
     182              : {
     183              :         struct lgfs2_inode *ip;
     184              :         struct inode_with_dups *id;
     185              :         osi_list_t *tmp, *x;
     186            0 :         struct metawalk_fxns pass1b_fxns_delete = {
     187              :                 .private = NULL,
     188              :                 .check_metalist = delete_metadata,
     189              :                 .check_data = delete_data,
     190              :                 .check_leaf = delete_leaf,
     191              :                 .check_eattr_indir = delete_eattr_indir,
     192              :                 .check_eattr_leaf = delete_eattr_leaf,
     193              :                 .check_eattr_entry = delete_eattr_entry,
     194              :                 .check_eattr_extentry = delete_eattr_extentry,
     195              :         };
     196              :         enum dup_ref_type this_ref;
     197              :         struct inode_info *ii;
     198              :         struct dir_info *di;
     199            0 :         int found_good_ref = 0;
     200              :         int q;
     201              : 
     202            0 :         osi_list_foreach_safe(tmp, ref_list, x) {
     203            0 :                 if (skip_this_pass || fsck_abort)
     204            0 :                         return;
     205              : 
     206            0 :                 id = osi_list_entry(tmp, struct inode_with_dups, list);
     207            0 :                 dh->dt = dt;
     208              : 
     209            0 :                 if (dh->ref_inode_count == 1) /* down to the last reference */
     210            0 :                         return;
     211              : 
     212            0 :                 this_ref = get_ref_type(id);
     213            0 :                 q = bitmap_type(cx->sdp, id->block_no);
     214            0 :                 if (inval)
     215            0 :                         log_warn( _("Invalid "));
     216              :                 /* FIXME: If we already found an acceptable reference to this
     217              :                  * block, we should really duplicate the block and fix all
     218              :                  * references to it in this inode.  Unfortunately, we would
     219              :                  * have to traverse the entire metadata tree to do that. */
     220            0 :                 if (acceptable_ref != REF_TYPES && /* If we're nuking all but
     221              :                                                       an acceptable reference
     222              :                                                       type and */
     223            0 :                     this_ref == acceptable_ref) { /* this ref is acceptable */
     224              :                         /* If this is an invalid inode, but not on the invalid
     225              :                            list, it's better to delete it. */
     226            0 :                         if (q == GFS2_BLKST_DINODE) {
     227            0 :                                 found_good_ref = 1;
     228            0 :                                 log_warn(_("Inode %s (%"PRIu64"/0x%"PRIx64")'s "
     229              :                                             "reference to block %"PRIu64" (0x%"PRIx64") "
     230              :                                             "as '%s' is acceptable.\n"),
     231              :                                           id->name,
     232              :                                           id->block_no, id->block_no, dt->block, dt->block,
     233              :                                           reftypes[this_ref]);
     234            0 :                                 continue; /* don't delete the dinode */
     235              :                         }
     236              :                 }
     237              :                 /* If this reference is from a system inode, for example, if
     238              :                    it's data or metadata inside a journal, the reference
     239              :                    should take priority over user dinodes that reference the
     240              :                    block. */
     241            0 :                 if (!found_good_ref && fsck_system_inode(cx->sdp, id->block_no)) {
     242            0 :                         found_good_ref = 1;
     243            0 :                         continue; /* don't delete the dinode */
     244              :                 }
     245            0 :                 log_warn(_("Inode %s (%"PRIu64"/0x%"PRIx64") references block "
     246              :                             "%"PRIu64" (0x%"PRIx64") as '%s', but the block is "
     247              :                             "really %s.\n"),
     248              :                           id->name, id->block_no, id->block_no, dt->block, dt->block,
     249              :                           reftypes[this_ref], reftypes[acceptable_ref]);
     250            0 :                 if (this_ref == REF_AS_EA) {
     251            0 :                         if (!(query(cx, _("Okay to remove extended attributes "
     252              :                                        "from %s inode %"PRIu64" (0x%"PRIx64")? (y/n) "),
     253              :                                      (inval ? _("invalidated") : ""),
     254              :                                     id->block_no, id->block_no))) {
     255            0 :                                 log_warn( _("The bad EA reference was not "
     256              :                                             "cleared."));
     257              :                                 /* delete the list entry so we don't leak
     258              :                                    memory but leave the reference count. If we
     259              :                                    decrement the ref count, we could get down
     260              :                                    to 1 and the dinode would be changed
     261              :                                    without a 'Yes' answer. */
     262              :                                 /* (dh->ref_inode_count)--;*/
     263            0 :                                 dup_listent_delete(dt, id);
     264            0 :                                 continue;
     265              :                         }
     266            0 :                 } else if (acceptable_ref == REF_TYPES &&
     267              :                            this_ref == REF_AS_DATA) {
     268            0 :                         clone_data_block(cx, dt, id);
     269            0 :                         dup_listent_delete(dt, id);
     270            0 :                         revise_dup_handler(cx, dt->block, dh);
     271            0 :                         continue;
     272            0 :                 } else if (!(query(cx, _("Okay to delete %s inode %"PRIu64" (0x%"PRIx64")? (y/n) "),
     273              :                                     (inval ? _("invalidated") : ""),
     274              :                                     id->block_no, id->block_no))) {
     275            0 :                         log_warn( _("The bad inode was not cleared."));
     276              :                         /* delete the list entry so we don't leak memory but
     277              :                            leave the reference count. If we decrement the
     278              :                            ref count, we could get down to 1 and the dinode
     279              :                            would be changed without a 'Yes' answer. */
     280              :                         /* (dh->ref_inode_count)--;*/
     281            0 :                         dup_listent_delete(dt, id);
     282            0 :                         continue;
     283              :                 }
     284            0 :                 if (q == GFS2_BLKST_FREE)
     285            0 :                         log_warn(_("Inode %"PRIu64" (0x%"PRIx64") was previously deleted.\n"),
     286              :                                  id->block_no, id->block_no);
     287            0 :                 else if (this_ref == REF_AS_EA)
     288            0 :                         log_warn(_("Pass1b is removing extended attributes from inode %"PRIu64" (0x%"PRIx64").\n"),
     289              :                                  id->block_no, id->block_no);
     290              :                 else
     291            0 :                         log_warn(_("Pass1b is deleting inode %"PRIu64" (0x%"PRIx64").\n"),
     292              :                                  id->block_no, id->block_no);
     293              : 
     294            0 :                 ip = fsck_load_inode(cx->sdp, id->block_no);
     295              :                 /* If we've already deleted this dinode, don't try to delete
     296              :                    it again. That could free blocks that used to be duplicate
     297              :                    references that are now resolved (and gone). */
     298            0 :                 if (q != GFS2_BLKST_FREE) {
     299              :                         /* If the inode's eattr pointer is to the duplicate
     300              :                            ref block, we don't want to call check_inode_eattr
     301              :                            because that would traverse the structure, and it's
     302              :                            not ours to do anymore; it rightly belongs to a
     303              :                            different dinode. On the other hand, if the dup
     304              :                            block is buried deep within the eattr structure
     305              :                            of this dinode, we need to traverse the structure
     306              :                            because it IS ours, and we need to remove all the
     307              :                            eattr leaf blocks: they do belong to us (except for
     308              :                            the duplicate referenced one, which is handled). */
     309            0 :                         if (ip->i_eattr == dt->block) {
     310            0 :                                 ip->i_eattr = 0;
     311            0 :                                 if (ip->i_blocks > 0)
     312            0 :                                         ip->i_blocks--;
     313            0 :                                 ip->i_flags &= ~GFS2_DIF_EA_INDIRECT;
     314            0 :                                 lgfs2_bmodified(ip->i_bh);
     315            0 :                                 dup_listent_delete(dt, id);
     316            0 :                                 (dh->ref_inode_count)--;
     317              :                         } else {
     318              :                                 /* Clear the EAs for the inode first */
     319            0 :                                 check_inode_eattr(cx, ip, &pass1b_fxns_delete);
     320            0 :                                 (dh->ref_inode_count)--;
     321              :                         }
     322              :                         /* If the reference was as metadata or data, we've got
     323              :                            a corrupt dinode that will be deleted. */
     324            0 :                         if ((this_ref != REF_AS_EA) &&
     325            0 :                             (inval || id->reftypecount[REF_AS_DATA] ||
     326            0 :                              id->reftypecount[REF_AS_META])) {
     327              :                                 /* Fix the bitmap first, while the inodetree
     328              :                                    and dirtree entries exist. That way, the
     329              :                                    bitmap_set will do proper accounting for
     330              :                                    the rgrp dinode count. */
     331            0 :                                 fsck_bitmap_set(cx, ip, ip->i_num.in_addr,
     332              :                                                 _("duplicate referencing bad"),
     333              :                                                 GFS2_BLKST_FREE);
     334              :                                 /* Remove the inode from the inode tree */
     335            0 :                                 ii = inodetree_find(cx, ip->i_num.in_addr);
     336            0 :                                 if (ii)
     337            0 :                                         inodetree_delete(cx, ii);
     338            0 :                                 di = dirtree_find(cx, ip->i_num.in_addr);
     339            0 :                                 if (di)
     340            0 :                                         dirtree_delete(cx, di);
     341            0 :                                 link1_set(&nlink1map, ip->i_num.in_addr,
     342              :                                           0);
     343              :                                 /* We delete the dup_handler inode count and
     344              :                                    duplicate id BEFORE clearing the metadata,
     345              :                                    because if this is the last reference to
     346              :                                    this metadata block, we need to traverse the
     347              :                                    tree and free the data blocks it references.
     348              :                                    However, we don't want to delete other
     349              :                                    duplicates that may be used by other
     350              :                                    dinodes. */
     351            0 :                                 (dh->ref_inode_count)--;
     352              :                                 /* FIXME: other option should be to duplicate
     353              :                                    the block for each duplicate and point the
     354              :                                    metadata at the cloned blocks */
     355            0 :                                 check_metatree(cx, ip, &pass1b_fxns_delete);
     356              :                         }
     357              :                 }
     358              :                 /* Now we've got to go through and delete any other duplicate
     359              :                    references from this dinode we're deleting. If we don't,
     360              :                    pass1b will discover the other duplicate record, try to
     361              :                    delete this dinode a second time, and this time its earlier
     362              :                    duplicate references won't be seen as duplicates anymore
     363              :                    (because they were eliminated earlier in pass1b). And so
     364              :                    the blocks will be mistakenly freed, when, in fact, they're
     365              :                    still being referenced by a valid dinode. */
     366            0 :                 if (this_ref != REF_AS_EA)
     367            0 :                         delete_all_dups(cx, ip);
     368            0 :                 fsck_inode_put(&ip); /* out, lgfs2_brelse, free */
     369              :         }
     370            0 :         return;
     371              : }
     372              : 
     373            0 : static int clone_check_meta(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
     374              :                             int *is_valid, int *was_duplicate, void *private)
     375              : {
     376            0 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     377            0 :         uint64_t block = iptr_block(iptr);
     378              : 
     379            0 :         *was_duplicate = 0;
     380            0 :         *is_valid = 1;
     381            0 :         *bh = lgfs2_bread(ip->i_sbd, block);
     382            0 :         return 0;
     383              : }
     384              : 
     385              : /* clone_data - clone a duplicate reference
     386              :  *
     387              :  * This function remembers the first reference to the specified block, and
     388              :  * clones all subsequent references to it (with permission).
     389              :  */
     390            0 : static int clone_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
     391              :                       uint64_t block, void *private,
     392              :                       struct lgfs2_buffer_head *bh, __be64 *ptr)
     393              : {
     394            0 :         struct clone_target *clonet = (struct clone_target *)private;
     395              :         struct lgfs2_buffer_head *clone_bh;
     396              :         uint64_t cloneblock;
     397              :         int error;
     398              : 
     399            0 :         if (block != clonet->dup_block)
     400            0 :                 return 0;
     401              : 
     402            0 :         if (clonet->first) {
     403            0 :                 log_debug(_("Inode %"PRIu64" (0x%"PRIx64")'s first reference to "
     404              :                             "block %"PRIu64" (0x%"PRIx64") is targeted for cloning.\n"),
     405              :                           ip->i_num.in_addr, ip->i_num.in_addr, block, block);
     406            0 :                 clonet->first = 0;
     407            0 :                 return 0;
     408              :         }
     409            0 :         log_err(_("Error: Inode %"PRIu64" (0x%"PRIx64")'s reference to block %"PRIu64
     410              :                   " (0x%"PRIx64") should be replaced with a clone.\n"),
     411              :                 ip->i_num.in_addr, ip->i_num.in_addr, block, block);
     412            0 :         if (query(cx, _("Okay to clone the duplicated reference? (y/n) "))) {
     413            0 :                 error = lgfs2_meta_alloc(ip, &cloneblock);
     414            0 :                 if (!error) {
     415            0 :                         clone_bh = lgfs2_bread(ip->i_sbd, clonet->dup_block);
     416            0 :                         if (clone_bh) {
     417            0 :                                 fsck_bitmap_set(cx, ip, cloneblock, _("data"),
     418              :                                                 GFS2_BLKST_USED);
     419            0 :                                 clone_bh->b_blocknr = cloneblock;
     420            0 :                                 lgfs2_bmodified(clone_bh);
     421            0 :                                 lgfs2_brelse(clone_bh);
     422              :                                 /* Now fix the reference: */
     423            0 :                                 *ptr = cpu_to_be64(cloneblock);
     424            0 :                                 lgfs2_bmodified(bh);
     425            0 :                                 log_err(_("Duplicate reference to block %"PRIu64
     426              :                                           " (0x%"PRIx64") was cloned to block %"PRIu64
     427              :                                           " (0x%"PRIx64").\n"),
     428              :                                         block, block, cloneblock, cloneblock);
     429            0 :                                 return 0;
     430              :                         }
     431              :                 }
     432            0 :                 log_err(_("Error: Unable to allocate a new data block.\n"));
     433            0 :                 if (!query(cx, _("Zero the reference instead? (y/n)"))) {
     434            0 :                         log_err(_("Duplicate reference to block %"PRIu64
     435              :                                   " (0x%"PRIx64") was not fixed.\n"),
     436              :                                 block, block);
     437            0 :                         return 0;
     438              :                 }
     439            0 :                 *ptr = 0;
     440            0 :                 lgfs2_bmodified(bh);
     441            0 :                 log_err(_("Duplicate reference to block %"PRIu64" (0x%"PRIx64") was zeroed.\n"),
     442              :                         block, block);
     443              :         } else {
     444            0 :                 log_err(_("Duplicate reference to block %"PRIu64" (0x%"PRIx64") was not fixed.\n"),
     445              :                         block, block);
     446              :         }
     447            0 :         return 0;
     448              : }
     449              : 
     450              : /* clone_dup_ref_in_inode - clone a duplicate reference within a single inode
     451              :  *
     452              :  * This function traverses the metadata tree of an inode, cloning all
     453              :  * but the first reference to a duplicate block reference.
     454              :  */
     455            0 : static void clone_dup_ref_in_inode(struct fsck_cx *cx, struct lgfs2_inode *ip, struct duptree *dt)
     456              : {
     457              :         int error;
     458            0 :         struct clone_target clonet = {.dup_block = dt->block, .first = 1};
     459            0 :         struct metawalk_fxns pass1b_fxns_clone = {
     460              :                 .private = &clonet,
     461              :                 .check_metalist = clone_check_meta,
     462              :                 .check_data = clone_data,
     463              :         };
     464              : 
     465            0 :         log_err(_("There are multiple references to block %"PRIu64" (0x%"PRIx64") in "
     466              :                   "inode %"PRIu64" (0x%"PRIx64")\n"),
     467              :                 ip->i_num.in_addr, ip->i_num.in_addr, dt->block, dt->block);
     468            0 :         error = check_metatree(cx, ip, &pass1b_fxns_clone);
     469            0 :         if (error) {
     470            0 :                 log_err(_("Error cloning duplicate reference(s) to block %"PRIu64
     471              :                           " (0x%"PRIx64").\n"), dt->block, dt->block);
     472              :         }
     473            0 : }
     474              : 
     475            0 : static int set_ip_bitmap(struct fsck_cx *cx, struct lgfs2_inode *ip)
     476              : {
     477            0 :         uint64_t block = ip->i_bh->b_blocknr;
     478              :         uint32_t mode;
     479              :         const char *ty;
     480              : 
     481            0 :         mode = ip->i_mode & S_IFMT;
     482              : 
     483            0 :         switch (mode) {
     484            0 :         case S_IFDIR:
     485            0 :                 ty = "directory";
     486            0 :                 break;
     487            0 :         case S_IFREG:
     488            0 :                 ty = "file";
     489            0 :                 break;
     490            0 :         case S_IFLNK:
     491            0 :                 ty = "symlink";
     492            0 :                 break;
     493            0 :         case S_IFBLK:
     494            0 :                 ty = "block device";
     495            0 :                 break;
     496            0 :         case S_IFCHR:
     497            0 :                 ty = "character device";
     498            0 :                 break;
     499            0 :         case S_IFIFO:
     500            0 :                 ty = "fifo";
     501            0 :                 break;
     502            0 :         case S_IFSOCK:
     503            0 :                 ty = "socket";
     504            0 :                 break;
     505            0 :         default:
     506            0 :                 return -EINVAL;
     507              :         }
     508            0 :         fsck_bitmap_set(cx, ip, block, ty, GFS2_BLKST_DINODE);
     509            0 :         return 0;
     510              : }
     511              : 
     512            0 : static void resolve_last_reference(struct fsck_cx *cx, struct duptree *dt,
     513              :                                    enum dup_ref_type acceptable_ref)
     514              : {
     515            0 :         struct lgfs2_sbd *sdp = cx->sdp;
     516              :         struct lgfs2_inode *ip;
     517              :         struct inode_with_dups *id;
     518              :         osi_list_t *tmp;
     519              :         int q;
     520              : 
     521            0 :         log_notice(_("Block %"PRIu64" (0x%"PRIx64") has only one remaining valid inode referencing it.\n"),
     522              :                    dt->block, dt->block);
     523              :         /* If we're down to a single reference (and not all references
     524              :            deleted, which may be the case of an inode that has only
     525              :            itself and a reference), we need to reset the block type
     526              :            from invalid to data or metadata. Start at the first one
     527              :            in the list, not the structure's place holder. */
     528            0 :         tmp = dt->ref_inode_list.next;
     529            0 :         id = osi_list_entry(tmp, struct inode_with_dups, list);
     530            0 :         log_debug(_("----------------------------------------------\n"
     531              :                      "Step 4. Set block type based on the remaining "
     532              :                      "reference in inode %"PRIu64" (0x%"PRIx64").\n"),
     533              :                   id->block_no, id->block_no);
     534            0 :         ip = fsck_load_inode(sdp, id->block_no);
     535              : 
     536            0 :         if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
     537            0 :                 clone_dup_ref_in_inode(cx, ip, dt);
     538              : 
     539            0 :         q = bitmap_type(sdp, id->block_no);
     540            0 :         if (q == GFS2_BLKST_FREE) {
     541            0 :                 log_debug(_("The remaining reference inode %"PRIu64" (0x%"PRIx64") was "
     542              :                              "already marked free.\n"),
     543              :                           id->block_no, id->block_no);
     544            0 :         } else if (id->reftypecount[REF_IS_INODE]) {
     545            0 :                 set_ip_bitmap(cx, ip);
     546            0 :         } else if (id->reftypecount[REF_AS_DATA]) {
     547            0 :                 fsck_bitmap_set(cx, ip, dt->block,  _("reference-repaired data"),
     548              :                                 GFS2_BLKST_USED);
     549            0 :         } else if (id->reftypecount[REF_AS_META]) {
     550            0 :                 if (is_dir(ip))
     551            0 :                         fsck_bitmap_set(cx, ip, dt->block,
     552              :                                         _("reference-repaired leaf"),
     553              :                                         GFS2_BLKST_USED);
     554              :                 else
     555            0 :                         fsck_bitmap_set(cx, ip, dt->block,
     556              :                                         _("reference-repaired indirect"),
     557              :                                         GFS2_BLKST_USED);
     558              :         } else {
     559            0 :                 if (acceptable_ref == REF_AS_EA)
     560            0 :                         fsck_bitmap_set(cx, ip, dt->block,
     561              :                                         _("reference-repaired extended "
     562              :                                           "attribute"),
     563              :                                         GFS2_BLKST_USED);
     564              :                 else {
     565            0 :                         log_err(_("Error: The remaining reference to block "
     566              :                                   " %"PRIu64" (0x%"PRIx64") is as extended attribute, "
     567              :                                   "in inode %"PRIu64" (0x%"PRIx64") but the block is "
     568              :                                   "not an extended attribute block.\n"),
     569              :                                 dt->block, dt->block, id->block_no, id->block_no);
     570            0 :                         if (query(cx, _("Okay to remove the bad extended "
     571              :                                     "attribute from inode %"PRIu64" (0x%"PRIx64")? "
     572              :                                     "(y/n) "),
     573              :                                   id->block_no, id->block_no)) {
     574            0 :                                 ip->i_eattr = 0;
     575            0 :                                 ip->i_flags &= ~GFS2_DIF_EA_INDIRECT;
     576            0 :                                 ip->i_blocks--;
     577            0 :                                 lgfs2_bmodified(ip->i_bh);
     578            0 :                                 fsck_bitmap_set(cx, ip, dt->block,
     579              :                                                 _("reference-repaired EA"),
     580              :                                                 GFS2_BLKST_FREE);
     581            0 :                                 log_err(_("The bad extended attribute was "
     582              :                                           "removed.\n"));
     583              :                         } else {
     584            0 :                                 log_err(_("The bad extended attribute was not "
     585              :                                           "removed.\n"));
     586              :                         }
     587              :                 }
     588              :         }
     589            0 :         fsck_inode_put(&ip); /* out, lgfs2_brelse, free */
     590            0 :         log_debug(_("Done with duplicate reference to block 0x%"PRIx64"\n"), dt->block);
     591            0 :         dup_delete(cx, dt);
     592            0 : }
     593              : 
     594              : /* handle_dup_blk - handle a duplicate block reference.
     595              :  *
     596              :  * This function should resolve and delete the duplicate block reference given,
     597              :  * iow dt.
     598              :  */
     599            0 : static int handle_dup_blk(struct fsck_cx *cx, struct duptree *dt)
     600              : {
     601              :         osi_list_t *tmp;
     602            0 :         struct dup_handler dh = {0};
     603              :         struct lgfs2_buffer_head *bh;
     604              :         __be32 cmagic, ctype;
     605              :         enum dup_ref_type acceptable_ref;
     606              :         uint64_t dup_blk;
     607              : 
     608            0 :         dup_blk = dt->block;
     609            0 :         revise_dup_handler(cx, dup_blk, &dh);
     610              : 
     611              :         /* Log the duplicate references */
     612            0 :         log_notice(_("Block %"PRIu64" (0x%"PRIx64") has %d inodes referencing it"
     613              :                    " for a total of %d duplicate references:\n"),
     614              :                    dt->block, dt->block, dh.ref_inode_count, dh.ref_count);
     615              : 
     616            0 :         osi_list_foreach(tmp, &dt->ref_invinode_list)
     617            0 :                 log_inode_reference(dt, tmp, 1);
     618            0 :         osi_list_foreach(tmp, &dt->ref_inode_list)
     619            0 :                 log_inode_reference(dt, tmp, 0);
     620              : 
     621              :         /* Figure out the block type to see if we can eliminate references
     622              :            to a different type. In other words, if the duplicate block looks
     623              :            like metadata, we can delete dinodes that reference it as data.
     624              :            If the block doesn't look like metadata, we can eliminate any
     625              :            references to it as metadata.  Dinodes with such references are
     626              :            clearly corrupt and need to be deleted.
     627              :            And if we're left with a single reference, problem solved. */
     628            0 :         bh = lgfs2_bread(cx->sdp, dt->block);
     629            0 :         cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
     630            0 :         ctype = ((struct gfs2_meta_header *)(bh->b_data))->mh_type;
     631            0 :         lgfs2_brelse(bh);
     632              : 
     633              :         /* If this is a dinode, any references to it (except in directory
     634              :            entries) are invalid and should be deleted. */
     635            0 :         if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
     636            0 :             be32_to_cpu(ctype) == GFS2_METATYPE_DI)
     637            0 :                 acceptable_ref = REF_IS_INODE;
     638            0 :         else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
     639            0 :             (be32_to_cpu(ctype) == GFS2_METATYPE_EA ||
     640            0 :              be32_to_cpu(ctype) == GFS2_METATYPE_ED))
     641            0 :                 acceptable_ref = REF_AS_EA;
     642            0 :         else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
     643            0 :                  be32_to_cpu(ctype) <= GFS2_METATYPE_QC)
     644            0 :                 acceptable_ref = REF_AS_META;
     645              :         else
     646            0 :                 acceptable_ref = REF_AS_DATA;
     647              : 
     648              :         /* A single reference to the block implies a possible situation where
     649              :            a data pointer points to a metadata block.  In other words, the
     650              :            duplicate reference in the file system is (1) Metadata block X and
     651              :            (2) A dinode reference such as a data pointer pointing to block X.
     652              :            We can't really check for that in pass1 because user data might
     653              :            just _look_ like metadata by coincidence, and at the time we're
     654              :            checking, we might not have processed the referenced block.
     655              :            Here in pass1b we're sure. */
     656              :         /* Another possibility here is that there is a single reference
     657              :            because all the other metadata references were in inodes that got
     658              :            invalidated for other reasons, such as bad pointers.  So we need to
     659              :            make sure at this point that any inode deletes reverse out any
     660              :            duplicate reference before we get to this point. */
     661              : 
     662              :         /* Step 1 - eliminate references from inodes that are not valid.
     663              :          *          This may be because they were deleted due to corruption.
     664              :          *          All block types are unacceptable, so we use REF_TYPES.
     665              :          */
     666            0 :         if (dh.ref_count > 1) {
     667            0 :                 log_debug(_("----------------------------------------------\n"
     668              :                              "Step 1: Eliminate references to block %"PRIu64" "
     669              :                              "(0x%"PRIx64") that were previously marked "
     670              :                              "invalid.\n"),
     671              :                           dt->block, dt->block);
     672            0 :                 resolve_dup_references(cx, dt, &dt->ref_invinode_list,
     673              :                                        &dh, 1, REF_TYPES);
     674            0 :                 revise_dup_handler(cx, dup_blk, &dh);
     675              :         }
     676              :         /* Step 2 - eliminate reference from inodes that reference it as the
     677              :          *          wrong type.  For example, a data file referencing it as
     678              :          *          a data block, but it's really a metadata block.  Or a
     679              :          *          directory inode referencing a data block as a leaf block.
     680              :          */
     681            0 :         if (dh.ref_count > 1) {
     682            0 :                 log_debug(_("----------------------------------------------\n"
     683              :                              "Step 2: Eliminate references to block %"PRIu64" "
     684              :                              "(0x%"PRIx64") that need the wrong block type.\n"),
     685              :                           dt->block, dt->block);
     686            0 :                 resolve_dup_references(cx, dt, &dt->ref_inode_list, &dh, 0,
     687              :                                        acceptable_ref);
     688            0 :                 revise_dup_handler(cx, dup_blk, &dh);
     689              :         }
     690              :         /* Step 3 - We have multiple dinodes referencing it as the correct
     691              :          *          type.  Just blast one of them.
     692              :          *          All block types are fair game, so we use REF_TYPES.
     693              :          */
     694            0 :         if (dh.ref_count > 1) {
     695            0 :                 log_debug(_("----------------------------------------------\n"
     696              :                              "Step 3: Choose one reference to block %"PRIu64" "
     697              :                              "(0x%"PRIx64") to keep.\n"),
     698              :                           dt->block, dt->block);
     699            0 :                 resolve_dup_references(cx, dt, &dt->ref_inode_list, &dh, 0,
     700              :                                        REF_TYPES);
     701            0 :                 revise_dup_handler(cx, dup_blk, &dh);
     702              :         }
     703              :         /* If there's still a last remaining reference, and it's a valid
     704              :            reference, use it to determine the correct block type for our
     705              :            blockmap and bitmap. */
     706            0 :         if (dh.ref_inode_count == 1 && !osi_list_empty(&dt->ref_inode_list)) {
     707            0 :                 resolve_last_reference(cx, dt, acceptable_ref);
     708              :         } else {
     709              :                 /* They may have answered no and not fixed all references. */
     710            0 :                 log_debug( _("All duplicate references to block 0x%"PRIx64" were processed.\n"), dup_blk);
     711            0 :                 if (dh.ref_count) {
     712            0 :                         log_debug(_("Done with duplicate reference to block "
     713              :                                     "0x%"PRIx64", but %d references remain.\n"),
     714              :                                   dup_blk, dh.ref_count);
     715              :                 } else {
     716            0 :                         log_notice(_("Block %"PRIu64" (0x%"PRIx64") has no more "
     717              :                                       "references; Marking as 'free'.\n"),
     718              :                                    dup_blk, dup_blk);
     719            0 :                         if (dh.dt)
     720            0 :                                 dup_delete(cx, dh.dt);
     721            0 :                         check_n_fix_bitmap(cx, NULL, dup_blk, 0,
     722              :                                            GFS2_BLKST_FREE);
     723              :                 }
     724              :         }
     725            0 :         return 0;
     726              : }
     727              : 
     728            0 : static int check_leaf_refs(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     729              :                            void *private)
     730              : {
     731            0 :         return add_duplicate_ref(cx, ip, block, REF_AS_META, 1, INODE_VALID);
     732              : }
     733              : 
     734            0 : static int check_metalist_refs(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h,
     735              :                                int *is_valid, int *was_duplicate, void *private)
     736              : {
     737            0 :         struct lgfs2_inode *ip = iptr.ipt_ip;
     738            0 :         uint64_t block = iptr_block(iptr);
     739              : 
     740            0 :         *was_duplicate = 0;
     741            0 :         *is_valid = 1;
     742            0 :         return add_duplicate_ref(cx, ip, block, REF_AS_META, 1, INODE_VALID);
     743              : }
     744              : 
     745            0 : static int check_data_refs(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
     746              :                            uint64_t block, void *private,
     747              :                            struct lgfs2_buffer_head *bh, __be64 *ptr)
     748              : {
     749            0 :         return add_duplicate_ref(cx, ip, block, REF_AS_DATA, 1, INODE_VALID);
     750              : }
     751              : 
     752            0 : static int check_eattr_indir_refs(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     753              :                                   uint64_t parent,
     754              :                                   struct lgfs2_buffer_head **bh, void *private)
     755              : {
     756            0 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     757              :         int error;
     758              : 
     759            0 :         error = add_duplicate_ref(cx, ip, block, REF_AS_EA, 1, INODE_VALID);
     760            0 :         if (!error)
     761            0 :                 *bh = lgfs2_bread(sdp, block);
     762              : 
     763            0 :         return error;
     764              : }
     765              : 
     766            0 : static int check_eattr_leaf_refs(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     767              :                                  uint64_t parent, struct lgfs2_buffer_head **bh,
     768              :                                  void *private)
     769              : {
     770            0 :         struct lgfs2_sbd *sdp = ip->i_sbd;
     771              :         int error;
     772              : 
     773            0 :         error = add_duplicate_ref(cx, ip, block, REF_AS_EA, 1, INODE_VALID);
     774            0 :         if (!error)
     775            0 :                 *bh = lgfs2_bread(sdp, block);
     776            0 :         return error;
     777              : }
     778              : 
     779            0 : static int check_eattr_entry_refs(struct fsck_cx *cx, struct lgfs2_inode *ip,
     780              :                                   struct lgfs2_buffer_head *leaf_bh,
     781              :                                   struct gfs2_ea_header *ea_hdr,
     782              :                                   struct gfs2_ea_header *ea_hdr_prev,
     783              :                                   void *private)
     784              : {
     785            0 :         return 0;
     786              : }
     787              : 
     788            0 : static int check_eattr_extentry_refs(struct fsck_cx *cx, struct lgfs2_inode *ip, int i,
     789              :                                      __be64 *ea_data_ptr,
     790              :                                      struct lgfs2_buffer_head *leaf_bh,
     791              :                                      uint32_t tot_ealen,
     792              :                                      struct gfs2_ea_header *ea_hdr,
     793              :                                      struct gfs2_ea_header *ea_hdr_prev,
     794              :                                      void *private)
     795              : {
     796            0 :         uint64_t block = be64_to_cpu(*ea_data_ptr);
     797              : 
     798              :         /* This is a case where a bad return code may be sent back, and
     799              :            behavior has changed. Before, if add_duplicate_ref returned a
     800              :            non-zero return code, the caller would delete the eattr from
     801              :            the blockmap. In this case, we should be okay because the only
     802              :            error possible is a malloc that fails, in which case we don't
     803              :            want to delete the eattr anyway. */
     804            0 :         return add_duplicate_ref(cx, ip, block, REF_AS_EA, 1, INODE_VALID);
     805              : }
     806              : 
     807              : /* Finds all references to duplicate blocks in the metadata */
     808              : /* Finds all references to duplicate blocks in the metadata */
     809            0 : static int find_block_ref(struct fsck_cx *cx, uint64_t inode)
     810              : {
     811              :         struct lgfs2_inode *ip;
     812            0 :         int error = 0;
     813            0 :         struct metawalk_fxns find_refs = {
     814              :                 .private = NULL,
     815              :                 .check_leaf = check_leaf_refs,
     816              :                 .check_metalist = check_metalist_refs,
     817              :                 .check_data = check_data_refs,
     818              :                 .check_eattr_indir = check_eattr_indir_refs,
     819              :                 .check_eattr_leaf = check_eattr_leaf_refs,
     820              :                 .check_eattr_entry = check_eattr_entry_refs,
     821              :                 .check_eattr_extentry = check_eattr_extentry_refs,
     822              :         };
     823              : 
     824            0 :         ip = fsck_load_inode(cx->sdp, inode); /* lgfs2_bread, inode_get */
     825              : 
     826              :         /* double-check the meta header just to be sure it's metadata */
     827            0 :         if (ip->i_magic != GFS2_MAGIC ||
     828            0 :             ip->i_mh_type != GFS2_METATYPE_DI) {
     829            0 :                 log_debug(_("Block %"PRIu64" (0x%"PRIx64") is not a dinode.\n"),
     830              :                           inode, inode);
     831            0 :                 error = 1;
     832            0 :                 goto out;
     833              :         }
     834              :         /* Check to see if this inode was referenced by another by mistake */
     835            0 :         add_duplicate_ref(cx, ip, inode, REF_IS_INODE, 1, INODE_VALID);
     836              : 
     837              :         /* Check this dinode's metadata for references to known duplicates */
     838            0 :         error = check_metatree(cx, ip, &find_refs);
     839            0 :         if (error < 0)
     840            0 :                 stack;
     841              : 
     842              :         /* Check for ea references in the inode */
     843            0 :         if (!error)
     844            0 :                 error = check_inode_eattr(cx, ip, &find_refs);
     845              : 
     846            0 : out:
     847            0 :         fsck_inode_put(&ip); /* out, lgfs2_brelse, free */
     848            0 :         return error;
     849              : }
     850              : 
     851              : /* Pass 1b handles finding the previous inode for a duplicate block
     852              :  * When found, store the inodes pointing to the duplicate block for
     853              :  * use in pass2 */
     854           57 : int pass1b(struct fsck_cx *cx)
     855              : {
     856           57 :         struct lgfs2_sbd *sdp = cx->sdp;
     857              :         struct duptree *dt;
     858              :         uint64_t i;
     859              :         int q;
     860              :         struct osi_node *n;
     861           57 :         int rc = FSCK_OK;
     862              : 
     863           57 :         log_info( _("Looking for duplicate blocks...\n"));
     864              : 
     865              :         /* If there were no dups in the bitmap, we don't need to do anymore */
     866           57 :         if (cx->dup_blocks.osi_node == NULL) {
     867           57 :                 log_info( _("No duplicate blocks found\n"));
     868           57 :                 return FSCK_OK;
     869              :         }
     870              : 
     871              :         /* Rescan the fs looking for pointers to blocks that are in
     872              :          * the duplicate block map */
     873            0 :         log_info( _("Scanning filesystem for inodes containing duplicate blocks...\n"));
     874            0 :         log_debug(_("Filesystem has %"PRIu64" (0x%"PRIx64") blocks total\n"),
     875              :                   last_fs_block, last_fs_block);
     876            0 :         for (i = 0; i < last_fs_block; i++) {
     877            0 :                 if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
     878            0 :                         goto out;
     879              : 
     880            0 :                 if (dups_found_first == dups_found) {
     881            0 :                         log_debug(_("Found all %d original references to "
     882              :                                     "duplicates.\n"), dups_found);
     883            0 :                         break;
     884              :                 }
     885            0 :                 q = bitmap_type(sdp, i);
     886              : 
     887            0 :                 if (q == GFS2_BLKST_FREE || q == GFS2_BLKST_USED || q < 0)
     888            0 :                         continue;
     889              : 
     890            0 :                 if (q == GFS2_BLKST_UNLINKED) {
     891            0 :                         log_debug(_("Error: block %"PRIu64" (0x%"PRIx64") is still marked UNLINKED.\n"),
     892              :                                   i, i);
     893            0 :                         return FSCK_ERROR;
     894              :                 }
     895              : 
     896            0 :                 display_progress(i);
     897            0 :                 if (find_block_ref(cx, i) < 0) {
     898            0 :                         stack;
     899            0 :                         rc = FSCK_ERROR;
     900            0 :                         goto out;
     901              :                 }
     902              :         }
     903              : 
     904              :         /* Fix dups here - it's going to slow things down a lot to fix
     905              :          * it later */
     906            0 :         log_info( _("Handling duplicate blocks\n"));
     907            0 : out:
     908              :         /* Resolve all duplicates by clearing out the dup tree */
     909            0 :         while ((n = osi_first(&cx->dup_blocks))) {
     910            0 :                 dt = (struct duptree *)n;
     911            0 :                 if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
     912            0 :                         handle_dup_blk(cx, dt);
     913              :         }
     914            0 :         return rc;
     915              : }
        

Generated by: LCOV version 2.0-1