LCOV - code coverage report
Current view: top level - fsck - link.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 33 92 35.9 %
Date: 2023-10-25 12:04:14 Functions: 3 4 75.0 %

          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         954 : int link1_set(struct bmap *bmap, uint64_t bblock, int mark)
      22             : {
      23             :         static unsigned char *byte;
      24             :         static uint64_t b;
      25             : 
      26         954 :         if (!bmap)
      27           0 :                 return 0;
      28         954 :         if (bblock > bmap->size)
      29           1 :                 return -1;
      30             : 
      31         953 :         byte = bmap->map + BLOCKMAP_SIZE1(bblock);
      32         953 :         b = BLOCKMAP_BYTE_OFFSET1(bblock);
      33         953 :         *byte &= ~(BLOCKMAP_MASK1 << b);
      34         953 :         *byte |= (mark & BLOCKMAP_MASK1) << b;
      35         953 :         return 0;
      36             : }
      37             : 
      38         700 : 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         700 :         if (is_dir(ip)) {
      44         224 :                 di = dirtree_find(cx, ip->i_num.in_addr);
      45         224 :                 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         224 :                 di->di_nlink = ip->i_nlink;
      52         224 :                 return 0;
      53             :         }
      54         476 :         if (ip->i_nlink == 1) {
      55         476 :                 link1_set(&nlink1map, ip->i_num.in_addr, 1);
      56         476 :                 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        1036 : int incr_link_count(struct fsck_cx *cx, struct lgfs2_inum no, struct lgfs2_inode *ip, const char *why)
      81             : {
      82        1036 :         struct inode_info *ii = NULL;
      83        1036 :         uint64_t referenced_from = ip ? ip->i_num.in_addr : 0;
      84             :         struct dir_info *di;
      85             :         struct lgfs2_inode *link_ip;
      86             : 
      87        1036 :         di = dirtree_find(cx, no.in_addr);
      88        1036 :         if (di) {
      89         560 :                 if (di->dinode.in_formal_ino != no.in_formal_ino)
      90           0 :                         return INCR_LINK_INO_MISMATCH;
      91             : 
      92         560 :                 di->counted_links++;
      93         560 :                 whyincr(no.in_addr, why, referenced_from, di->counted_links);
      94         560 :                 return INCR_LINK_GOOD;
      95             :         }
      96         476 :         ii = inodetree_find(cx, no.in_addr);
      97             :         /* If the list has entries, look for one that matches inode_no */
      98         476 :         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         476 :         if (link1_type(&clink1map, no.in_addr) != 1) {
     107         476 :                 link1_set(&clink1map, no.in_addr, 1);
     108         476 :                 whyincr(no.in_addr, why, referenced_from, 1);
     109         476 :                 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 1.14