LCOV - code coverage report
Current view: top level - fsck - link.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 35.9 % 92 33
Test Date: 2024-03-07 16:24:06 Functions: 75.0 % 4 3

            Line data    Source code
       1              : #include "clusterautoconfig.h"
       2              : 
       3              : #include <inttypes.h>
       4              : #include <stdlib.h>
       5              : #include <stdint.h>
       6              : #include <string.h>
       7              : #include <unistd.h>
       8              : #include <libintl.h>
       9              : #define _(String) gettext(String)
      10              : 
      11              : #include <logging.h>
      12              : #include "libgfs2.h"
      13              : #include "fsck.h"
      14              : #include "inode_hash.h"
      15              : #include "link.h"
      16              : #include "util.h"
      17              : 
      18              : struct bmap nlink1map = { 0 }; /* map of dinodes with nlink == 1 */
      19              : struct bmap clink1map = { 0 }; /* map of dinodes w/counted links == 1 */
      20              : 
      21          970 : int link1_set(struct bmap *bmap, uint64_t bblock, int mark)
      22              : {
      23              :         static unsigned char *byte;
      24              :         static uint64_t b;
      25              : 
      26          970 :         if (!bmap)
      27            0 :                 return 0;
      28          970 :         if (bblock > bmap->size)
      29            1 :                 return -1;
      30              : 
      31          969 :         byte = bmap->map + BLOCKMAP_SIZE1(bblock);
      32          969 :         b = BLOCKMAP_BYTE_OFFSET1(bblock);
      33          969 :         *byte &= ~(BLOCKMAP_MASK1 << b);
      34          969 :         *byte |= (mark & BLOCKMAP_MASK1) << b;
      35          969 :         return 0;
      36              : }
      37              : 
      38          712 : int set_di_nlink(struct fsck_cx *cx, struct lgfs2_inode *ip)
      39              : {
      40              :         struct inode_info *ii;
      41              :         struct dir_info *di;
      42              : 
      43          712 :         if (is_dir(ip)) {
      44          228 :                 di = dirtree_find(cx, ip->i_num.in_addr);
      45          228 :                 if (di == NULL) {
      46            0 :                         log_err(_("Error: directory %"PRIu64" (0x%"PRIx64") is not "
      47              :                                   "in the dir_tree (set).\n"),
      48              :                                 ip->i_num.in_addr, ip->i_num.in_addr);
      49            0 :                         return -1;
      50              :                 }
      51          228 :                 di->di_nlink = ip->i_nlink;
      52          228 :                 return 0;
      53              :         }
      54          484 :         if (ip->i_nlink == 1) {
      55          484 :                 link1_set(&nlink1map, ip->i_num.in_addr, 1);
      56          484 :                 return 0;
      57              :         }
      58              :         /*log_debug( _("Setting link count to %u for %" PRIu64
      59              :           " (0x%" PRIx64 ")\n"), count, inode_no, inode_no);*/
      60              :         /* If the list has entries, look for one that matches inode_no */
      61            0 :         ii = inodetree_find(cx, ip->i_num.in_addr);
      62            0 :         if (!ii) {
      63            0 :                 struct lgfs2_inum no = ip->i_num;
      64            0 :                 ii = inodetree_insert(cx, no);
      65              :         }
      66            0 :         if (ii)
      67            0 :                 ii->di_nlink = ip->i_nlink;
      68              :         else
      69            0 :                 return -1;
      70            0 :         return 0;
      71              : }
      72              : 
      73              : /* I'm making whyincr a macro rather than function so that the debug output
      74              :  * matches older versions. */
      75              : #define whyincr(no_addr, why, referenced_from, counted_links)             \
      76              :         log_debug(_("Dir (0x%"PRIx64") incremented counted links to %u "  \
      77              :                     "for (0x%"PRIx64") via %s\n"),                        \
      78              :                   referenced_from, counted_links, no_addr, why);
      79              : 
      80         1054 : int incr_link_count(struct fsck_cx *cx, struct lgfs2_inum no, struct lgfs2_inode *ip, const char *why)
      81              : {
      82         1054 :         struct inode_info *ii = NULL;
      83         1054 :         uint64_t referenced_from = ip ? ip->i_num.in_addr : 0;
      84              :         struct dir_info *di;
      85              :         struct lgfs2_inode *link_ip;
      86              : 
      87         1054 :         di = dirtree_find(cx, no.in_addr);
      88         1054 :         if (di) {
      89          570 :                 if (di->dinode.in_formal_ino != no.in_formal_ino)
      90            0 :                         return INCR_LINK_INO_MISMATCH;
      91              : 
      92          570 :                 di->counted_links++;
      93          570 :                 whyincr(no.in_addr, why, referenced_from, di->counted_links);
      94          570 :                 return INCR_LINK_GOOD;
      95              :         }
      96          484 :         ii = inodetree_find(cx, no.in_addr);
      97              :         /* If the list has entries, look for one that matches inode_no */
      98          484 :         if (ii) {
      99            0 :                 if (ii->num.in_formal_ino != no.in_formal_ino)
     100            0 :                         return INCR_LINK_INO_MISMATCH;
     101              : 
     102            0 :                 ii->counted_links++;
     103            0 :                 whyincr(no.in_addr, why, referenced_from, ii->counted_links);
     104            0 :                 return INCR_LINK_GOOD;
     105              :         }
     106          484 :         if (link1_type(&clink1map, no.in_addr) != 1) {
     107          484 :                 link1_set(&clink1map, no.in_addr, 1);
     108          484 :                 whyincr(no.in_addr, why, referenced_from, 1);
     109          484 :                 return INCR_LINK_GOOD;
     110              :         }
     111              : 
     112            0 :         link_ip = fsck_load_inode(ip->i_sbd, no.in_addr);
     113              :         /* Check formal ino against dinode before adding to inode tree. */
     114            0 :         if (no.in_formal_ino != link_ip->i_num.in_formal_ino) {
     115            0 :                 fsck_inode_put(&link_ip);
     116            0 :                 return INCR_LINK_INO_MISMATCH; /* inode mismatch */
     117              :         }
     118              :         /* Move it from the link1 maps to a real inode tree entry */
     119            0 :         link1_set(&nlink1map, no.in_addr, 0);
     120            0 :         link1_set(&clink1map, no.in_addr, 0);
     121              : 
     122              :         /* If no match was found, it must be a hard link. In theory, it can't
     123              :            be a duplicate because those were resolved in pass1b. Add a new
     124              :            inodetree entry and set its counted links to 2 */
     125            0 :         ii = inodetree_insert(cx, no);
     126            0 :         if (!ii) {
     127            0 :                 log_debug(_("Ref: 0x%"PRIx64" Error incrementing link for 0x%"PRIx64"\n"),
     128              :                           referenced_from, no.in_addr);
     129            0 :                 fsck_inode_put(&link_ip);
     130            0 :                 return INCR_LINK_BAD;
     131              :         }
     132            0 :         ii->num.in_addr = link_ip->i_num.in_addr;
     133            0 :         ii->num.in_formal_ino = link_ip->i_num.in_formal_ino;
     134            0 :         fsck_inode_put(&link_ip);
     135            0 :         ii->di_nlink = 1; /* Must be 1 or it wouldn't have gotten into the
     136              :                              nlink1map */
     137            0 :         ii->counted_links = 2;
     138            0 :         whyincr(no.in_addr, why, referenced_from, ii->counted_links);
     139              :         /* We transitioned a dentry link count from 1 to 2, and we know it's
     140              :            not a directory. But the new reference has the correct formal
     141              :            inode number, so the first reference is suspect: we need to
     142              :            check it in case it's a bad reference, and not just a hard link. */
     143            0 :         return INCR_LINK_CHECK_ORIG;
     144              : }
     145              : 
     146              : #define whydecr(no_addr, why, referenced_from, counted_links)             \
     147              :         log_debug(_("Dir (0x%"PRIx64") decremented counted links to %u "  \
     148              :                     "for (0x%"PRIx64") via %s\n"),                        \
     149              :                   referenced_from, counted_links, no_addr, why);
     150              : 
     151            0 : int decr_link_count(struct fsck_cx *cx, uint64_t inode_no, uint64_t referenced_from, const char *why)
     152              : {
     153            0 :         struct inode_info *ii = NULL;
     154              :         struct dir_info *di;
     155              : 
     156            0 :         di = dirtree_find(cx, inode_no);
     157            0 :         if (di) {
     158            0 :                 if (!di->counted_links) {
     159            0 :                         log_debug(_("Dir 0x%"PRIx64"'s link to 0x%"PRIx64" via %s is zero!\n"),
     160              :                                   referenced_from, inode_no, why);
     161            0 :                         return 0;
     162              :                 }
     163            0 :                 di->counted_links--;
     164            0 :                 whydecr(inode_no, why, referenced_from, di->counted_links);
     165            0 :                 return 0;
     166              :         }
     167              : 
     168            0 :         ii = inodetree_find(cx, inode_no);
     169              :         /* If the list has entries, look for one that matches
     170              :          * inode_no */
     171            0 :         if (ii) {
     172            0 :                 if (!ii->counted_links) {
     173            0 :                         log_debug(_("Dir 0x%"PRIx64"'s link to 0x%"PRIx64" via %s is zero!\n"),
     174              :                                   referenced_from, inode_no, why);
     175            0 :                         return 0;
     176              :                 }
     177            0 :                 ii->counted_links--;
     178            0 :                 whydecr(inode_no, why, referenced_from, ii->counted_links);
     179            0 :                 return 0;
     180              :         }
     181            0 :         if (link1_type(&clink1map, inode_no) == 1) { /* 1 -> 0 */
     182            0 :                 link1_set(&clink1map, inode_no, 0);
     183            0 :                 whydecr(inode_no, why, referenced_from, 0);
     184            0 :                 return 0;
     185              :         }
     186              : 
     187            0 :         log_debug(_("No match found when decrementing link for (0x%"PRIx64")!\n"), inode_no);
     188            0 :         return -1;
     189              : 
     190              : }
     191              : 
     192              : 
        

Generated by: LCOV version 2.0-1