LCOV - code coverage report
Current view: top level - fsck - pass4.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 28.2 % 131 37
Test Date: 2024-03-07 16:24:06 Functions: 62.5 % 8 5

            Line data    Source code
       1              : #include "clusterautoconfig.h"
       2              : 
       3              : #include <inttypes.h>
       4              : #include <stdlib.h>
       5              : #include <stdio.h>
       6              : #include <libintl.h>
       7              : #define _(String) gettext(String)
       8              : 
       9              : #include <logging.h>
      10              : #include "libgfs2.h"
      11              : #include "fsck.h"
      12              : #include "link.h"
      13              : #include "lost_n_found.h"
      14              : #include "inode_hash.h"
      15              : #include "metawalk.h"
      16              : #include "util.h"
      17              : #include "afterpass1_common.h"
      18              : 
      19              : static struct metawalk_fxns pass4_fxns_delete = {
      20              :         .private = NULL,
      21              :         .check_metalist = delete_metadata,
      22              :         .check_data = delete_data,
      23              :         .check_eattr_indir = delete_eattr_indir,
      24              :         .check_eattr_leaf = delete_eattr_leaf,
      25              : };
      26              : 
      27              : /* Updates the link count of an inode to what the fsck has seen for
      28              :  * link count */
      29            0 : static int fix_link_count(uint32_t counted_links, struct lgfs2_inode *ip)
      30              : {
      31            0 :         log_info(_("Fixing inode link count (%d->%d) for %"PRIu64" (0x%"PRIx64") \n"),
      32              :                  ip->i_nlink, counted_links, ip->i_num.in_addr, ip->i_num.in_addr);
      33            0 :         if (ip->i_nlink == counted_links)
      34            0 :                 return 0;
      35            0 :         ip->i_nlink = counted_links;
      36            0 :         lgfs2_bmodified(ip->i_bh);
      37              : 
      38            0 :         log_debug(_("Changing inode %"PRIu64" (0x%"PRIx64") to have %u links\n"),
      39              :                   ip->i_num.in_addr, ip->i_num.in_addr, counted_links);
      40            0 :         return 0;
      41              : }
      42              : 
      43              : /**
      44              :  * handle_unlinked - handle an unlinked dinode
      45              :  *
      46              :  * Note: We need to pass in *counted_links here, not counted_links because
      47              :  *       add_inode_to_lf may be called here, and that might change the original
      48              :  *       value, whether that's in the dirtree or the inodetree.
      49              :  *
      50              :  * Returns: 1 if caller should do "continue", 0 if not.
      51              :  */
      52            0 : static int handle_unlinked(struct fsck_cx *cx, uint64_t no_addr,
      53              :                            uint32_t *counted_links, int *lf_addition)
      54              : {
      55            0 :         struct lgfs2_sbd *sdp = cx->sdp;
      56              :         struct lgfs2_inode *ip;
      57              :         int q;
      58              : 
      59            0 :         log_err(_("Found unlinked inode at %"PRIu64" (0x%"PRIx64")\n"),
      60              :                 no_addr, no_addr);
      61            0 :         q = bitmap_type(sdp, no_addr);
      62            0 :         if (q == GFS2_BLKST_FREE) {
      63            0 :                 log_err(_("Unlinked inode %"PRIu64" (0x%"PRIx64") contains bad blocks\n"),
      64              :                         no_addr, no_addr);
      65            0 :                 if (query(cx, _("Delete unlinked inode with bad blocks? (y/n) "))) {
      66            0 :                         ip = fsck_load_inode(sdp, no_addr);
      67            0 :                         check_inode_eattr(cx, ip, &pass4_fxns_delete);
      68            0 :                         check_metatree(cx, ip, &pass4_fxns_delete);
      69            0 :                         fsck_bitmap_set(cx, ip, no_addr, _("bad unlinked"),
      70              :                                         GFS2_BLKST_FREE);
      71            0 :                         fsck_inode_put(&ip);
      72            0 :                         return 1;
      73              :                 } else {
      74            0 :                         log_err(_("Unlinked inode with bad blocks not cleared\n"));
      75              :                 }
      76              :         }
      77            0 :         if (q != GFS2_BLKST_DINODE) {
      78            0 :                 log_err(_("Unlinked block %"PRIu64" (0x%"PRIx64") marked as inode is not an inode (%d)\n"),
      79              :                         no_addr, no_addr, q);
      80            0 :                 ip = fsck_load_inode(sdp, no_addr);
      81            0 :                 if (query(cx, _("Delete unlinked inode? (y/n) "))) {
      82            0 :                         check_inode_eattr(cx, ip, &pass4_fxns_delete);
      83            0 :                         check_metatree(cx, ip, &pass4_fxns_delete);
      84            0 :                         fsck_bitmap_set(cx, ip, no_addr, _("invalid unlinked"),
      85              :                                         GFS2_BLKST_FREE);
      86            0 :                         fsck_inode_put(&ip);
      87            0 :                         log_err( _("The inode was deleted\n"));
      88              :                 } else {
      89            0 :                         log_err( _("The inode was not deleted\n"));
      90            0 :                         fsck_inode_put(&ip);
      91              :                 }
      92            0 :                 return 1;
      93              :         }
      94            0 :         ip = fsck_load_inode(sdp, no_addr);
      95              : 
      96              :         /* We don't want to clear zero-size files with eattrs - there might be
      97              :            relevent info in them. */
      98            0 :         if (!ip->i_size && !ip->i_eattr){
      99            0 :                 log_err( _("Unlinked inode has zero size\n"));
     100            0 :                 if (query(cx, _("Clear zero-size unlinked inode? (y/n) "))) {
     101            0 :                         fsck_bitmap_set(cx, ip, no_addr, _("unlinked zero-length"),
     102              :                                         GFS2_BLKST_FREE);
     103            0 :                         fsck_inode_put(&ip);
     104            0 :                         return 1;
     105              :                 }
     106              :         }
     107            0 :         if (query(cx, _("Add unlinked inode to lost+found? (y/n)"))) {
     108            0 :                 if (add_inode_to_lf(cx, ip)) {
     109            0 :                         stack;
     110            0 :                         fsck_inode_put(&ip);
     111            0 :                         return -1;
     112              :                 } else {
     113            0 :                         fix_link_count(*counted_links, ip);
     114            0 :                         *lf_addition = 1;
     115              :                 }
     116              :         } else
     117            0 :                 log_err( _("Unlinked inode left unlinked\n"));
     118            0 :         fsck_inode_put(&ip);
     119            0 :         return 0;
     120              : }
     121              : 
     122            0 : static void handle_inconsist(struct fsck_cx *cx, uint64_t no_addr,
     123              :                              uint32_t *di_nlink, uint32_t counted_links)
     124              : {
     125            0 :         log_err(_("Link count inconsistent for inode %"PRIu64" (0x%"PRIx64") has %u but fsck found %u.\n"),
     126              :                 no_addr, no_addr, *di_nlink, counted_links);
     127              :         /* Read in the inode, adjust the link count, and write it back out */
     128            0 :         if (query(cx, _("Update link count for inode %"PRIu64" (0x%"PRIx64")? (y/n) "),
     129              :                   no_addr, no_addr)) {
     130              :                 struct lgfs2_inode *ip;
     131              : 
     132            0 :                 ip = fsck_load_inode(cx->sdp, no_addr); /* lgfs2_bread, inode_get */
     133            0 :                 fix_link_count(counted_links, ip);
     134            0 :                 *di_nlink = counted_links;
     135            0 :                 fsck_inode_put(&ip); /* out, lgfs2_brelse, free */
     136            0 :                 log_warn(_("Link count updated to %d for inode %"PRIu64" (0x%"PRIx64")\n"),
     137              :                          *di_nlink, no_addr, no_addr);
     138              :         } else {
     139            0 :                 log_err(_("Link count for inode %"PRIu64" (0x%"PRIx64") still incorrect\n"),
     140              :                         no_addr, no_addr);
     141              :         }
     142            0 : }
     143              : 
     144          171 : static int adjust_lf_links(struct fsck_cx *cx, int lf_addition)
     145              : {
     146              :         struct dir_info *lf_di;
     147              : 
     148          171 :         if (lf_dip == NULL)
     149          171 :                 return 0;
     150              : 
     151            0 :         if (!lf_addition)
     152            0 :                 return 0;
     153              : 
     154            0 :         if (!(lf_di = dirtree_find(cx, lf_dip->i_num.in_addr))) {
     155            0 :                 log_crit(_("Unable to find lost+found inode in "
     156              :                            "inode_hash!!\n"));
     157            0 :                 return -1;
     158              :         } else {
     159            0 :                 fix_link_count(lf_di->counted_links, lf_dip);
     160              :         }
     161            0 :         return 0;
     162              : }
     163              : 
     164           57 : static int scan_inode_list(struct fsck_cx *cx)
     165              : {
     166           57 :         struct osi_node *tmp, *next = NULL;
     167              :         struct inode_info *ii;
     168           57 :         int lf_addition = 0;
     169              : 
     170              :         /* FIXME: should probably factor this out into a generic
     171              :          * scanning fxn */
     172           57 :         for (tmp = osi_first(&cx->inodetree); tmp; tmp = next) {
     173            0 :                 if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
     174            0 :                         return 0;
     175            0 :                 next = osi_next(tmp);
     176            0 :                 ii = (struct inode_info *)tmp;
     177            0 :                 if (ii->counted_links == 0) {
     178            0 :                         if (handle_unlinked(cx, ii->num.in_addr,
     179              :                                             &ii->counted_links, &lf_addition))
     180            0 :                                 continue;
     181              :                 } /* if (ii->counted_links == 0) */
     182            0 :                 else if (ii->di_nlink != ii->counted_links) {
     183            0 :                         handle_inconsist(cx, ii->num.in_addr,
     184              :                                          &ii->di_nlink, ii->counted_links);
     185              :                 }
     186            0 :                 log_debug(_("block %"PRIu64" (0x%"PRIx64") has link count %d\n"),
     187              :                           ii->num.in_addr, ii->num.in_addr, ii->di_nlink);
     188              :         } /* osi_list_foreach(tmp, list) */
     189              : 
     190           57 :         return adjust_lf_links(cx, lf_addition);
     191              : }
     192              : 
     193           57 : static int scan_dir_list(struct fsck_cx *cx)
     194              : {
     195           57 :         struct osi_node *tmp, *next = NULL;
     196              :         struct dir_info *di;
     197           57 :         int lf_addition = 0;
     198              : 
     199              :         /* FIXME: should probably factor this out into a generic
     200              :          * scanning fxn */
     201          285 :         for (tmp = osi_first(&cx->dirtree); tmp; tmp = next) {
     202          228 :                 if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
     203            0 :                         return 0;
     204          228 :                 next = osi_next(tmp);
     205          228 :                 di = (struct dir_info *)tmp;
     206          228 :                 if (di->counted_links == 0) {
     207            0 :                         if (handle_unlinked(cx, di->dinode.in_addr,
     208              :                                             &di->counted_links, &lf_addition))
     209            0 :                                 continue;
     210          228 :                 } else if (di->di_nlink != di->counted_links) {
     211            0 :                         handle_inconsist(cx, di->dinode.in_addr,
     212              :                                          &di->di_nlink, di->counted_links);
     213              :                 }
     214          228 :                 log_debug(_("block %"PRIu64" (0x%"PRIx64") has link count %d\n"),
     215              :                           di->dinode.in_addr, di->dinode.in_addr, di->di_nlink);
     216              :         } /* osi_list_foreach(tmp, list) */
     217              : 
     218           57 :         return adjust_lf_links(cx, lf_addition);
     219              : }
     220              : 
     221           57 : static int scan_nlink1_list(struct fsck_cx *cx)
     222              : {
     223              :         uint64_t blk;
     224              :         uint32_t counted_links;
     225           57 :         int lf_addition = 0;
     226              : 
     227    482881449 :         for (blk = 0; blk < last_fs_block; blk++) {
     228    482881392 :                 if (skip_this_pass || fsck_abort)
     229            0 :                         return 0;
     230    482881392 :                 if (link1_type(&nlink1map, blk) == 0)
     231    482880908 :                         continue;
     232              : 
     233          484 :                 if (link1_type(&clink1map, blk) == 0) {
     234              :                         /* In other cases, counted_links is a pointer to a
     235              :                            real count that gets incremented when it's added
     236              :                            to lost+found. In this case, however, there's not a
     237              :                            real count, so we fake it out to be 1. */
     238            0 :                         counted_links = 1;
     239            0 :                         if (handle_unlinked(cx, blk, &counted_links, &lf_addition))
     240            0 :                                 continue;
     241              :                 }
     242              :         }
     243           57 :         return adjust_lf_links(cx, lf_addition);
     244              : }
     245              : 
     246              : /**
     247              :  * pass4 - Check reference counts (pass 2 & 6 in current fsck)
     248              :  *
     249              :  * handle unreferenced files
     250              :  * lost+found errors (missing, not a directory, no space)
     251              :  * adjust link count
     252              :  * handle unreferenced inodes of other types
     253              :  * handle bad blocks
     254              :  */
     255           57 : int pass4(struct fsck_cx *cx)
     256              : {
     257           57 :         if (lf_dip)
     258            0 :                 log_debug( _("At beginning of pass4, lost+found entries is %u\n"),
     259              :                                   lf_dip->i_entries);
     260           57 :         log_info( _("Checking inode reference counts: multi-links.\n"));
     261           57 :         if (scan_inode_list(cx)) {
     262            0 :                 stack;
     263            0 :                 return FSCK_ERROR;
     264              :         }
     265           57 :         log_info( _("Checking inode reference counts: directories.\n"));
     266           57 :         if (scan_dir_list(cx)) {
     267            0 :                 stack;
     268            0 :                 return FSCK_ERROR;
     269              :         }
     270           57 :         log_info( _("Checking inode reference counts: normal links.\n"));
     271           57 :         if (scan_nlink1_list(cx)) {
     272            0 :                 stack;
     273            0 :                 return FSCK_ERROR;
     274              :         }
     275              : 
     276           57 :         if (lf_dip)
     277            0 :                 log_debug( _("At end of pass4, lost+found entries is %u\n"),
     278              :                                   lf_dip->i_entries);
     279           57 :         return FSCK_OK;
     280              : }
        

Generated by: LCOV version 2.0-1