LCOV - code coverage report
Current view: top level - fsck - pass1b.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 7 362 1.9 %
Date: 2023-10-25 12:04:14 Functions: 1 21 4.8 %

          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          56 : int pass1b(struct fsck_cx *cx)
     855             : {
     856          56 :         struct lgfs2_sbd *sdp = cx->sdp;
     857             :         struct duptree *dt;
     858             :         uint64_t i;
     859             :         int q;
     860             :         struct osi_node *n;
     861          56 :         int rc = FSCK_OK;
     862             : 
     863          56 :         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          56 :         if (cx->dup_blocks.osi_node == NULL) {
     867          56 :                 log_info( _("No duplicate blocks found\n"));
     868          56 :                 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 1.14