LCOV - code coverage report
Current view: top level - fsck - pass3.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 36 128 28.1 %
Date: 2023-09-27 13:48:55 Functions: 2 3 66.7 %

          Line data    Source code
       1             : #include "clusterautoconfig.h"
       2             : 
       3             : #include <stdio.h>
       4             : #include <stdlib.h>
       5             : #include <inttypes.h>
       6             : #include <string.h>
       7             : #include <dirent.h>
       8             : #include <libintl.h>
       9             : #define _(String) gettext(String)
      10             : 
      11             : #include <logging.h>
      12             : #include "libgfs2.h"
      13             : #include "osi_list.h"
      14             : #include "fsck.h"
      15             : #include "lost_n_found.h"
      16             : #include "link.h"
      17             : #include "metawalk.h"
      18             : #include "util.h"
      19             : #include "afterpass1_common.h"
      20             : 
      21           0 : static int attach_dotdot_to(struct fsck_cx *cx, uint64_t newdotdot,
      22             :                             uint64_t olddotdot, uint64_t block)
      23             : {
      24           0 :         const char *filename = "..";
      25           0 :         int filename_len = 2;
      26             :         int err;
      27             :         struct lgfs2_inode *ip, *pip;
      28             :         struct lgfs2_inum no;
      29             : 
      30           0 :         ip = fsck_load_inode(cx->sdp, block);
      31           0 :         pip = fsck_load_inode(cx->sdp, newdotdot);
      32             :         /* FIXME: Need to add some interactive
      33             :          * options here and come up with a
      34             :          * good default for non-interactive */
      35             :         /* FIXME: do i need to correct the
      36             :          * '..' entry for this directory in
      37             :          * this case? */
      38             : 
      39           0 :         if (lgfs2_dirent_del(ip, filename, filename_len))
      40           0 :                 log_warn( _("Unable to remove \"..\" directory entry.\n"));
      41             :         else
      42           0 :                 decr_link_count(cx, olddotdot, block, _("old \"..\""));
      43           0 :         no = pip->i_num;
      44           0 :         err = lgfs2_dir_add(ip, filename, filename_len, &no, DT_DIR);
      45           0 :         if (err) {
      46           0 :                 log_err(_("Error adding directory %s: %s\n"),
      47             :                         filename, strerror(errno));
      48           0 :                 exit(FSCK_ERROR);
      49             :         }
      50           0 :         incr_link_count(cx, no, ip, _("new \"..\""));
      51           0 :         fsck_inode_put(&ip);
      52           0 :         fsck_inode_put(&pip);
      53           0 :         return 0;
      54             : }
      55             : 
      56         112 : static struct dir_info *mark_and_return_parent(struct fsck_cx *cx, struct dir_info *di)
      57             : {
      58         112 :         struct lgfs2_sbd *sdp = cx->sdp;
      59             :         struct dir_info *pdi;
      60             :         int q_dotdot, q_treewalk;
      61         112 :         int error = 0;
      62             :         struct dir_info *dt_dotdot, *dt_treewalk;
      63             : 
      64         112 :         di->checked = 1;
      65             : 
      66         112 :         if (!di->treewalk_parent)
      67           0 :                 return NULL;
      68             : 
      69         112 :         if (di->dotdot_parent.in_addr == di->treewalk_parent) {
      70         112 :                 q_dotdot = bitmap_type(sdp, di->dotdot_parent.in_addr);
      71         112 :                 if (q_dotdot != GFS2_BLKST_DINODE) {
      72           0 :                         log_err(_("Orphaned directory at block %"PRIu64" (0x%"PRIx64") "
      73             :                                   "moved to lost+found\n"),
      74             :                                 di->dinode.in_addr, di->dinode.in_addr);
      75           0 :                         return NULL;
      76             :                 }
      77         112 :                 goto out;
      78             :         }
      79             : 
      80           0 :         log_warn(_("Directory '..' and treewalk connections disagree for inode %"PRIu64" (0x%"PRIx64")\n"),
      81             :                  di->dinode.in_addr, di->dinode.in_addr);
      82           0 :         log_notice(_("'..' has %"PRIu64" (0x%"PRIx64"), treewalk has %"PRIu64" (0x%"PRIx64")\n"),
      83             :                    di->dotdot_parent.in_addr, di->dotdot_parent.in_addr, di->treewalk_parent, di->treewalk_parent);
      84           0 :         q_dotdot = bitmap_type(sdp, di->dotdot_parent.in_addr);
      85           0 :         dt_dotdot = dirtree_find(cx, di->dotdot_parent.in_addr);
      86           0 :         q_treewalk = bitmap_type(sdp, di->treewalk_parent);
      87           0 :         dt_treewalk = dirtree_find(cx, di->treewalk_parent);
      88             :         /* if the dotdot entry isn't a directory, but the
      89             :          * treewalk is, treewalk is correct - if the treewalk
      90             :          * entry isn't a directory, but the dotdot is, dotdot
      91             :          * is correct - if both are directories, which do we
      92             :          * choose? if neither are directories, we have a
      93             :          * problem - need to move this directory into lost+found
      94             :          */
      95           0 :         if (q_dotdot != GFS2_BLKST_DINODE || dt_dotdot == NULL) {
      96           0 :                 if (q_treewalk != GFS2_BLKST_DINODE) {
      97           0 :                         log_err( _("Orphaned directory, move to "
      98             :                                    "lost+found\n"));
      99           0 :                         return NULL;
     100             :                 } else {
     101           0 :                         log_warn(_("Treewalk parent is correct, fixing dotdot -> %"PRIu64" (0x%"PRIx64")\n"),
     102             :                                  di->treewalk_parent, di->treewalk_parent);
     103           0 :                         attach_dotdot_to(cx, di->treewalk_parent,
     104             :                                          di->dotdot_parent.in_addr,
     105             :                                          di->dinode.in_addr);
     106           0 :                         di->dotdot_parent.in_addr = di->treewalk_parent;
     107             :                 }
     108           0 :                 goto out;
     109             :         }
     110           0 :         if (dt_treewalk) {
     111           0 :                 log_err( _("Both .. and treewalk parents are directories, "
     112             :                            "going with treewalk...\n"));
     113           0 :                 attach_dotdot_to(cx, di->treewalk_parent,
     114             :                                  di->dotdot_parent.in_addr,
     115             :                                  di->dinode.in_addr);
     116           0 :                 di->dotdot_parent.in_addr = di->treewalk_parent;
     117           0 :                 goto out;
     118             :         }
     119           0 :         log_warn( _(".. parent is valid, but treewalk is bad - reattaching to "
     120             :                     "lost+found"));
     121             : 
     122             :         /* FIXME: add a dinode for this entry instead? */
     123             : 
     124           0 :         if (!query(cx, _("Remove directory entry for bad inode %"PRIu64" (0x%"PRIx64") "
     125             :                      "in %"PRIu64" (0x%"PRIx64")? (y/n)"),
     126             :                    di->dinode.in_addr, di->dinode.in_addr,
     127             :                    di->treewalk_parent, di->treewalk_parent)) {
     128           0 :                 log_err( _("Directory entry to invalid inode remains\n"));
     129           0 :                 return NULL;
     130             :         }
     131           0 :         error = remove_dentry_from_dir(cx, di->treewalk_parent, di->dinode.in_addr);
     132           0 :         if (error < 0) {
     133           0 :                 stack;
     134           0 :                 return NULL;
     135             :         }
     136           0 :         if (error > 0)
     137           0 :                 log_warn(_("Unable to find dentry for block %"PRIu64" (0x%"PRIx64") "
     138             :                            "in %"PRIu64" (0x%"PRIx64")\n"),
     139             :                          di->dinode.in_addr, di->dinode.in_addr,
     140             :                          di->treewalk_parent, di->treewalk_parent);
     141           0 :         log_warn( _("Directory entry removed\n"));
     142           0 :         log_info( _("Marking directory unlinked\n"));
     143             : 
     144           0 :         return NULL;
     145             : 
     146         112 : out:
     147         112 :         pdi = dirtree_find(cx, di->dotdot_parent.in_addr);
     148             : 
     149         112 :         return pdi;
     150             : }
     151             : 
     152             : /**
     153             :  * pass3 - check connectivity of directories
     154             :  *
     155             :  * handle disconnected directories
     156             :  * handle lost+found directory errors (missing, not a directory, no space)
     157             :  */
     158          56 : int pass3(struct fsck_cx *cx)
     159             : {
     160          56 :         struct lgfs2_sbd *sdp = cx->sdp;
     161          56 :         struct osi_node *tmp, *next = NULL;
     162             :         struct dir_info *di, *tdi;
     163             :         struct lgfs2_inode *ip;
     164             :         int q;
     165             : 
     166          56 :         di = dirtree_find(cx, sdp->md.rooti->i_num.in_addr);
     167          56 :         if (di) {
     168          56 :                 log_info( _("Marking root inode connected\n"));
     169          56 :                 di->checked = 1;
     170             :         }
     171          56 :         di = dirtree_find(cx, sdp->master_dir->i_num.in_addr);
     172          56 :         if (di) {
     173          56 :                 log_info(_("Marking master directory inode connected\n"));
     174          56 :                 di->checked = 1;
     175             :         }
     176             :         /* Go through the directory list, working up through the parents
     177             :          * until we find one that's been checked already.  If we don't
     178             :          * find a parent, put in lost+found.
     179             :          */
     180          56 :         log_info( _("Checking directory linkage.\n"));
     181         280 :         for (tmp = osi_first(&cx->dirtree); tmp; tmp = next) {
     182         224 :                 next = osi_next(tmp);
     183         224 :                 di = (struct dir_info *)tmp;
     184         336 :                 while (!di->checked) {
     185             :                         /* FIXME: Change this so it returns success or
     186             :                          * failure and put the parent inode in a
     187             :                          * param */
     188         112 :                         if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
     189           0 :                                 return FSCK_OK;
     190         112 :                         tdi = mark_and_return_parent(cx, di);
     191             : 
     192         112 :                         if (tdi) {
     193         112 :                                 log_debug(_("Directory at block %"PRIu64" (0x%"PRIx64") connected\n"),
     194             :                                           di->dinode.in_addr, di->dinode.in_addr);
     195         112 :                                 di = tdi;
     196         112 :                                 continue;
     197             :                         }
     198           0 :                         q = bitmap_type(sdp, di->dinode.in_addr);
     199           0 :                         ip = fsck_load_inode(sdp, di->dinode.in_addr);
     200           0 :                         if (q == GFS2_BLKST_FREE) {
     201           0 :                                 log_err( _("Found unlinked directory "
     202             :                                            "containing bad block at block %"PRIu64
     203             :                                            " (0x%"PRIx64")\n"),
     204             :                                         di->dinode.in_addr, di->dinode.in_addr);
     205           0 :                                 if (query(cx, _("Clear unlinked directory "
     206             :                                            "with bad blocks? (y/n) "))) {
     207           0 :                                         log_warn(_("inode %"PRIu64" (0x%"PRIx64") is "
     208             :                                                    "now marked as free\n"),
     209             :                                                  di->dinode.in_addr,
     210             :                                                  di->dinode.in_addr);
     211           0 :                                         check_n_fix_bitmap(cx, ip->i_rgd,
     212             :                                                            di->dinode.in_addr,
     213             :                                                            0, GFS2_BLKST_FREE);
     214           0 :                                         fsck_inode_put(&ip);
     215           0 :                                         break;
     216             :                                 } else
     217           0 :                                         log_err( _("Unlinked directory with bad block remains\n"));
     218             :                         }
     219           0 :                         if (q != GFS2_BLKST_DINODE) {
     220           0 :                                 log_err( _("Unlinked block marked as an inode "
     221             :                                            "is not an inode\n"));
     222           0 :                                 if (!query(cx, _("Clear the unlinked block? (y/n) "))) {
     223           0 :                                         log_err( _("The block was not "
     224             :                                                    "cleared\n"));
     225           0 :                                         fsck_inode_put(&ip);
     226           0 :                                         break;
     227             :                                 }
     228           0 :                                 log_warn( _("inode %"PRIu64" (0x%"PRIx64") is now "
     229             :                                             "marked as free\n"),
     230             :                                          di->dinode.in_addr, di->dinode.in_addr);
     231           0 :                                 check_n_fix_bitmap(cx, ip->i_rgd,
     232             :                                                    di->dinode.in_addr, 0,
     233             :                                                    GFS2_BLKST_FREE);
     234           0 :                                 log_err( _("The block was cleared\n"));
     235           0 :                                 fsck_inode_put(&ip);
     236           0 :                                 break;
     237             :                         }
     238             : 
     239           0 :                         log_err(_("Found unlinked directory at block %"PRIu64" (0x%"PRIx64")\n"),
     240             :                                 di->dinode.in_addr, di->dinode.in_addr);
     241             :                         /* Don't skip zero size directories with eattrs */
     242           0 :                         if (!ip->i_size && !ip->i_eattr){
     243           0 :                                 log_err( _("Unlinked directory has zero "
     244             :                                            "size.\n"));
     245           0 :                                 if (query(cx, _("Remove zero-size unlinked "
     246             :                                             "directory? (y/n) "))) {
     247           0 :                                         fsck_bitmap_set(cx, ip, di->dinode.in_addr,
     248             :                                                 _("zero-sized unlinked inode"),
     249             :                                                         GFS2_BLKST_FREE);
     250           0 :                                         fsck_inode_put(&ip);
     251           0 :                                         break;
     252             :                                 } else {
     253           0 :                                         log_err( _("Zero-size unlinked "
     254             :                                                    "directory remains\n"));
     255             :                                 }
     256             :                         }
     257           0 :                         if (query(cx, _("Add unlinked directory to "
     258             :                                     "lost+found? (y/n) "))) {
     259           0 :                                 if (add_inode_to_lf(cx, ip)) {
     260           0 :                                         fsck_inode_put(&ip);
     261           0 :                                         stack;
     262           0 :                                         return FSCK_ERROR;
     263             :                                 }
     264           0 :                                 log_warn( _("Directory relinked to lost+found\n"));
     265             :                         } else {
     266           0 :                                 log_err( _("Unlinked directory remains unlinked\n"));
     267             :                         }
     268           0 :                         fsck_inode_put(&ip);
     269           0 :                         break;
     270             :                 }
     271             :         }
     272          56 :         if (lf_dip) {
     273           0 :                 log_debug( _("At end of pass3, lost+found entries is %u\n"),
     274             :                                   lf_dip->i_entries);
     275             :         }
     276          56 :         return FSCK_OK;
     277             : }

Generated by: LCOV version 1.14