LCOV - code coverage report
Current view: top level - fsck - pass3.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 28.1 % 128 36
Test Date: 2024-03-07 16:24:06 Functions: 66.7 % 3 2

            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          114 : static struct dir_info *mark_and_return_parent(struct fsck_cx *cx, struct dir_info *di)
      57              : {
      58          114 :         struct lgfs2_sbd *sdp = cx->sdp;
      59              :         struct dir_info *pdi;
      60              :         int q_dotdot, q_treewalk;
      61          114 :         int error = 0;
      62              :         struct dir_info *dt_dotdot, *dt_treewalk;
      63              : 
      64          114 :         di->checked = 1;
      65              : 
      66          114 :         if (!di->treewalk_parent)
      67            0 :                 return NULL;
      68              : 
      69          114 :         if (di->dotdot_parent.in_addr == di->treewalk_parent) {
      70          114 :                 q_dotdot = bitmap_type(sdp, di->dotdot_parent.in_addr);
      71          114 :                 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          114 :                 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          114 : out:
     147          114 :         pdi = dirtree_find(cx, di->dotdot_parent.in_addr);
     148              : 
     149          114 :         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           57 : int pass3(struct fsck_cx *cx)
     159              : {
     160           57 :         struct lgfs2_sbd *sdp = cx->sdp;
     161           57 :         struct osi_node *tmp, *next = NULL;
     162              :         struct dir_info *di, *tdi;
     163              :         struct lgfs2_inode *ip;
     164              :         int q;
     165              : 
     166           57 :         di = dirtree_find(cx, sdp->md.rooti->i_num.in_addr);
     167           57 :         if (di) {
     168           57 :                 log_info( _("Marking root inode connected\n"));
     169           57 :                 di->checked = 1;
     170              :         }
     171           57 :         di = dirtree_find(cx, sdp->master_dir->i_num.in_addr);
     172           57 :         if (di) {
     173           57 :                 log_info(_("Marking master directory inode connected\n"));
     174           57 :                 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           57 :         log_info( _("Checking directory linkage.\n"));
     181          285 :         for (tmp = osi_first(&cx->dirtree); tmp; tmp = next) {
     182          228 :                 next = osi_next(tmp);
     183          228 :                 di = (struct dir_info *)tmp;
     184          342 :                 while (!di->checked) {
     185              :                         /* FIXME: Change this so it returns success or
     186              :                          * failure and put the parent inode in a
     187              :                          * param */
     188          114 :                         if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
     189            0 :                                 return FSCK_OK;
     190          114 :                         tdi = mark_and_return_parent(cx, di);
     191              : 
     192          114 :                         if (tdi) {
     193          114 :                                 log_debug(_("Directory at block %"PRIu64" (0x%"PRIx64") connected\n"),
     194              :                                           di->dinode.in_addr, di->dinode.in_addr);
     195          114 :                                 di = tdi;
     196          114 :                                 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           57 :         if (lf_dip) {
     273            0 :                 log_debug( _("At end of pass3, lost+found entries is %u\n"),
     274              :                                   lf_dip->i_entries);
     275              :         }
     276           57 :         return FSCK_OK;
     277              : }
        

Generated by: LCOV version 2.0-1