LCOV - code coverage report
Current view: top level - fsck - util.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 80 349 22.9 %
Date: 2023-10-25 12:04:14 Functions: 8 19 42.1 %

          Line data    Source code
       1             : #include "clusterautoconfig.h"
       2             : 
       3             : #include <inttypes.h>
       4             : #include <stdlib.h>
       5             : #include <string.h>
       6             : #include <unistd.h>
       7             : #include <sys/time.h>
       8             : #include <stdio.h>
       9             : #include <stdarg.h>
      10             : #include <termios.h>
      11             : #include <libintl.h>
      12             : #include <ctype.h>
      13             : #define _(String) gettext(String)
      14             : 
      15             : #include <logging.h>
      16             : #include "libgfs2.h"
      17             : #include "metawalk.h"
      18             : #include "util.h"
      19             : 
      20             : const char *reftypes[REF_TYPES + 1] = {"data", "metadata",
      21             :                                        "an extended attribute", "an inode",
      22             :                                        "unimportant"};
      23             : 
      24           0 : void big_file_comfort(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t blks_checked)
      25             : {
      26             :         static struct timeval tv;
      27             :         static uint32_t seconds = 0;
      28             :         static uint64_t percent, fsize, chksize;
      29           0 :         uint64_t one_percent = 0;
      30             :         int i, cs;
      31           0 :         const char *human_abbrev = " KMGTPE";
      32             : 
      33           0 :         one_percent = ip->i_blocks / 100;
      34           0 :         if (blks_checked - last_reported_fblock < one_percent)
      35           0 :                 return;
      36             : 
      37           0 :         last_reported_fblock = blks_checked;
      38           0 :         gettimeofday(&tv, NULL);
      39           0 :         if (!seconds)
      40           0 :                 seconds = tv.tv_sec;
      41           0 :         if (tv.tv_sec == seconds)
      42           0 :                 return;
      43             : 
      44           0 :         fsize = ip->i_size;
      45           0 :         for (i = 0; i < 6 && fsize > 1024; i++)
      46           0 :                 fsize /= 1024;
      47           0 :         chksize = blks_checked * ip->i_sbd->sd_bsize;
      48           0 :         for (cs = 0; cs < 6 && chksize > 1024; cs++)
      49           0 :                 chksize /= 1024;
      50           0 :         seconds = tv.tv_sec;
      51           0 :         percent = (blks_checked * 100) / ip->i_blocks;
      52           0 :         log_notice(_("\rChecking %"PRIu64"%c of %"PRIu64"%c of file at %"PRIu64" (0x%"PRIx64")"
      53             :                       "- %"PRIu64" percent complete.                   \r"),
      54             :                    chksize, human_abbrev[cs], fsize, human_abbrev[i], ip->i_num.in_addr,
      55             :                    ip->i_num.in_addr, percent);
      56           0 :         fflush(stdout);
      57             : }
      58             : 
      59   477502169 : void display_progress(uint64_t block)
      60             : {
      61             :         static uint64_t one_percent = 0;
      62             :         static struct timeval tv;
      63             :         static uint32_t seconds = 0;
      64             : 
      65   477502169 :         if (!one_percent)
      66          56 :                 one_percent = last_fs_block / 100;
      67   477502169 :         if (!last_reported_block ||
      68   477502169 :             block - last_reported_block >= one_percent) {
      69        5671 :                 last_reported_block = block;
      70        5671 :                 gettimeofday(&tv, NULL);
      71        5671 :                 if (!seconds)
      72          56 :                         seconds = tv.tv_sec;
      73        5671 :                 if (tv.tv_sec - seconds) {
      74             :                         static uint64_t percent;
      75             : 
      76           5 :                         seconds = tv.tv_sec;
      77           5 :                         if (last_fs_block) {
      78           5 :                                 percent = (block * 100) / last_fs_block;
      79           5 :                                 log_notice(_("\r%"PRIu64" percent complete.\r"), percent);
      80           5 :                                 fflush(stdout);
      81             :                         }
      82             :                 }
      83             :         }
      84   477502169 : }
      85             : 
      86           0 : char fsck_getch(void)
      87             : {
      88             :         struct termios termattr, savetermattr;
      89             :         char ch;
      90             :         ssize_t size;
      91             : 
      92           0 :         tcgetattr (STDIN_FILENO, &termattr);
      93           0 :         savetermattr = termattr;
      94           0 :         termattr.c_lflag &= ~(ICANON | IEXTEN | ISIG);
      95           0 :         termattr.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
      96           0 :         termattr.c_cflag &= ~(CSIZE | PARENB);
      97           0 :         termattr.c_cflag |= CS8;
      98           0 :         termattr.c_oflag &= ~(OPOST);
      99           0 :         termattr.c_cc[VMIN] = 0;
     100           0 :         termattr.c_cc[VTIME] = 0;
     101             : 
     102           0 :         tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
     103             :         do {
     104           0 :                 size = read(STDIN_FILENO, &ch, 1);
     105           0 :                 if (size)
     106           0 :                         break;
     107           0 :                 usleep(50000);
     108           0 :         } while (!size);
     109             : 
     110           0 :         tcsetattr (STDIN_FILENO, TCSANOW, &savetermattr);
     111           0 :         return ch;
     112             : }
     113             : 
     114           0 : char generic_interrupt(const char *caller, const char *where,
     115             :                        const char *progress, const char *question,
     116             :                        const char *answers)
     117             : {
     118             :         fd_set rfds;
     119             :         struct timeval tv;
     120             :         char response;
     121             :         int err, i;
     122             : 
     123           0 :         FD_ZERO(&rfds);
     124           0 :         FD_SET(STDIN_FILENO, &rfds);
     125             : 
     126           0 :         tv.tv_sec = 0;
     127           0 :         tv.tv_usec = 0;
     128             :         /* Make sure there isn't extraneous input before asking the
     129             :          * user the question */
     130           0 :         while((err = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv))) {
     131           0 :                 if(err < 0) {
     132           0 :                         log_debug("Error in select() on stdin\n");
     133           0 :                         break;
     134             :                 }
     135           0 :                 if(read(STDIN_FILENO, &response, sizeof(char)) < 0) {
     136           0 :                         log_debug("Error in read() on stdin\n");
     137           0 :                         break;
     138             :                 }
     139             :         }
     140             :         while (1) {
     141           0 :                 printf("\n%s interrupted during %s:  ", caller, where);
     142           0 :                 if (progress)
     143           0 :                         printf("%s.\n", progress);
     144           0 :                 printf("%s", question);
     145             : 
     146             :                 /* Make sure query is printed out */
     147           0 :                 fflush(NULL);
     148           0 :                 response = fsck_getch();
     149           0 :                 printf("\n");
     150           0 :                 fflush(NULL);
     151           0 :                 if (strchr(answers, response))
     152           0 :                         break;
     153           0 :                 printf("Bad response, please type ");
     154           0 :                 for (i = 0; i < strlen(answers) - 1; i++)
     155           0 :                         printf("'%c', ", answers[i]);
     156           0 :                 printf(" or '%c'.\n", answers[i]);
     157             :         }
     158           0 :         return response;
     159             : }
     160             : 
     161             : /* fsck_query: Same as gfs2_query except it adjusts errors_found and
     162             :    errors_corrected. */
     163       32861 : int fsck_query(struct fsck_cx *cx, const char *format, ...)
     164             : {
     165             :         va_list args;
     166             :         char response;
     167       32861 :         int ret = 0;
     168             : 
     169       32861 :         errors_found++;
     170       32861 :         fsck_abort = 0;
     171       32861 :         if (cx->opts->yes) {
     172       32861 :                 errors_corrected++;
     173       32861 :                 return 1;
     174             :         }
     175           0 :         if (cx->opts->no)
     176           0 :                 return 0;
     177             : 
     178             :         while (1) {
     179           0 :                 va_start(args, format);
     180           0 :                 vprintf(format, args);
     181           0 :                 va_end(args);
     182             : 
     183             :                 /* Make sure query is printed out */
     184           0 :                 fflush(NULL);
     185           0 :                 response = fsck_getch();
     186             : 
     187           0 :                 printf("\n");
     188           0 :                 fflush(NULL);
     189           0 :                 if (response == 0x3) { /* if interrupted, by ctrl-c */
     190           0 :                         response = generic_interrupt("Question", "response",
     191             :                                                      NULL,
     192             :                                                      "Do you want to abort " \
     193             :                                                      "or continue (a/c)?",
     194             :                                                      "ac");
     195           0 :                         if (response == 'a') {
     196           0 :                                 ret = 0;
     197           0 :                                 fsck_abort = 1;
     198           0 :                                 break;
     199             :                         }
     200           0 :                         printf("Continuing.\n");
     201           0 :                 } else if (tolower(response) == 'y') {
     202           0 :                         errors_corrected++;
     203           0 :                         ret = 1;
     204           0 :                         break;
     205           0 :                 } else if (tolower(response) == 'n') {
     206           0 :                         ret = 0;
     207           0 :                         break;
     208             :                 } else {
     209           0 :                         printf("Bad response %d, please type 'y' or 'n'.\n",
     210             :                                response);
     211             :                 }
     212             :         }
     213           0 :         return ret;
     214             : }
     215             : 
     216             : /*
     217             :  * dup_set - Flag a block as a duplicate
     218             :  * We keep the references in a red/black tree.  We can't keep track of every
     219             :  * single inode in the file system, so the first time this function is called
     220             :  * will actually be for the second reference to the duplicated block.
     221             :  * This will return the number of references to the block.
     222             :  *
     223             :  * create - will be set if the call is supposed to create the reference. */
     224           0 : static struct duptree *dup_set(struct fsck_cx *cx, uint64_t dblock, int create)
     225             : {
     226           0 :         struct osi_node **newn = &cx->dup_blocks.osi_node, *parent = NULL;
     227             :         struct duptree *dt;
     228             : 
     229             :         /* Figure out where to put new node */
     230           0 :         while (*newn) {
     231           0 :                 struct duptree *cur = (struct duptree *)*newn;
     232             : 
     233           0 :                 parent = *newn;
     234           0 :                 if (dblock < cur->block)
     235           0 :                         newn = &((*newn)->osi_left);
     236           0 :                 else if (dblock > cur->block)
     237           0 :                         newn = &((*newn)->osi_right);
     238             :                 else
     239           0 :                         return cur;
     240             :         }
     241             : 
     242           0 :         if (!create)
     243           0 :                 return NULL;
     244           0 :         dt = malloc(sizeof(struct duptree));
     245           0 :         if (dt == NULL) {
     246           0 :                 log_crit( _("Unable to allocate duptree structure\n"));
     247           0 :                 return NULL;
     248             :         }
     249           0 :         dups_found++;
     250           0 :         memset(dt, 0, sizeof(struct duptree));
     251             :         /* Add new node and rebalance tree. */
     252           0 :         dt->block = dblock;
     253           0 :         dt->refs = 1; /* reference 1 is actually the reference we need to
     254             :                          discover in pass1b. */
     255           0 :         osi_list_init(&dt->ref_inode_list);
     256           0 :         osi_list_init(&dt->ref_invinode_list);
     257           0 :         osi_link_node(&dt->node, parent, newn);
     258           0 :         osi_insert_color(&dt->node, &cx->dup_blocks);
     259             : 
     260           0 :         return dt;
     261             : }
     262             : 
     263             : /**
     264             :  * find_dup_ref_inode - find a duplicate reference inode entry for an inode
     265             :  */
     266           0 : struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
     267             :                                            struct lgfs2_inode *ip)
     268             : {
     269             :         osi_list_t *ref;
     270             :         struct inode_with_dups *id;
     271             : 
     272           0 :         osi_list_foreach(ref, &dt->ref_invinode_list) {
     273           0 :                 id = osi_list_entry(ref, struct inode_with_dups, list);
     274             : 
     275           0 :                 if (id->block_no == ip->i_num.in_addr)
     276           0 :                         return id;
     277             :         }
     278           0 :         osi_list_foreach(ref, &dt->ref_inode_list) {
     279           0 :                 id = osi_list_entry(ref, struct inode_with_dups, list);
     280             : 
     281           0 :                 if (id->block_no == ip->i_num.in_addr)
     282           0 :                         return id;
     283             :         }
     284           0 :         return NULL;
     285             : }
     286             : 
     287             : /**
     288             :  * count_dup_meta_refs - count the number of remaining references as metadata
     289             :  */
     290           0 : int count_dup_meta_refs(struct duptree *dt)
     291             : {
     292             :         osi_list_t *ref;
     293             :         struct inode_with_dups *id;
     294           0 :         int metarefs = 0;
     295             : 
     296           0 :         osi_list_foreach(ref, &dt->ref_invinode_list) {
     297           0 :                 id = osi_list_entry(ref, struct inode_with_dups, list);
     298           0 :                 if (id->reftypecount[REF_AS_META])
     299           0 :                         metarefs++;
     300             :         }
     301           0 :         osi_list_foreach(ref, &dt->ref_inode_list) {
     302           0 :                 id = osi_list_entry(ref, struct inode_with_dups, list);
     303           0 :                 if (id->reftypecount[REF_AS_META])
     304           0 :                         metarefs++;
     305             :         }
     306           0 :         return metarefs;
     307             : }
     308             : 
     309             : /*
     310             :  * add_duplicate_ref - Add a duplicate reference to the duplicates tree list
     311             :  * A new element of the tree will be created as needed
     312             :  * When the first reference is discovered in pass1, it realizes it's a
     313             :  * duplicate but it has already forgotten where the first reference was.
     314             :  * So we need to recreate the duplicate reference structure if it's not there.
     315             :  * Later, in pass1b, it has to go back through the file system
     316             :  * and figure out those original references in order to resolve them.
     317             :  *
     318             :  * first - if 1, we're being called from pass1b, in which case we're trying
     319             :  *         to find the first reference to this block.  If 0, we're being
     320             :  *         called from pass1, which is the second reference, which determined
     321             :  *         it was a duplicate..
     322             :  */
     323           0 : int add_duplicate_ref(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
     324             :                       enum dup_ref_type reftype, int first, int inode_valid)
     325             : {
     326             :         struct inode_with_dups *id;
     327             :         struct duptree *dt;
     328             : 
     329           0 :         if (!valid_block_ip(ip, block))
     330           0 :                 return META_IS_GOOD;
     331             :         /* If this is not the first reference (i.e. all calls from pass1) we
     332             :            need to create the duplicate reference. If this is pass1b, we want
     333             :            to ignore references that aren't found. */
     334           0 :         dt = dup_set(cx, block, !first);
     335           0 :         if (!dt)        /* If this isn't a duplicate */
     336           0 :                 return META_IS_GOOD;
     337             : 
     338             :         /* If we found the duplicate reference but we've already discovered
     339             :            the first reference (in pass1b) and the other references in pass1,
     340             :            we don't need to count it, so just return. */
     341           0 :         if (dt->dup_flags & DUPFLAG_REF1_FOUND)
     342           0 :                 return META_IS_GOOD;
     343             : 
     344             :         /* Check for a previous reference to this duplicate */
     345           0 :         id = find_dup_ref_inode(dt, ip);
     346             : 
     347             :         /* We have to be careful here. The original referencing dinode may have
     348             :            deemed to be bad and deleted/freed in pass1. In that case, pass1b
     349             :            wouldn't discover the correct [deleted] original reference. In
     350             :            that case, we don't want to be confused and consider this second
     351             :            reference the same as the first. If we do, we'll never be able to
     352             :            resolve it. The first reference can't be the second reference. */
     353           0 :         if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
     354           0 :                 log_info(_("Original reference to block %"PRIu64" (0x%"PRIx64") was "
     355             :                            "either found to be bad and deleted, or else "
     356             :                            "a duplicate within the same inode.\n"),
     357             :                          block, block);
     358           0 :                 log_info(_("I'll consider the reference from inode %"PRIu64
     359             :                            " (0x%"PRIx64") the first reference.\n"),
     360             :                          ip->i_num.in_addr, ip->i_num.in_addr);
     361           0 :                 dt->dup_flags |= DUPFLAG_REF1_IS_DUPL;
     362           0 :                 dt->refs++;
     363             :         }
     364             : 
     365             :         /* The first time this is called from pass1 is actually the second
     366             :            reference.  When we go back in pass1b looking for the original
     367             :            reference, we don't want to increment the reference count because
     368             :            it's already accounted for. */
     369           0 :         if (first) {
     370           0 :                 dt->dup_flags |= DUPFLAG_REF1_FOUND;
     371           0 :                 dups_found_first++; /* We found another first ref. */
     372             :         } else {
     373           0 :                 dt->refs++;
     374             :         }
     375             : 
     376           0 :         if (id == NULL) {
     377             :                 /* Check for the inode on the invalid inode reference list. */
     378             :                 int q;
     379             : 
     380           0 :                 id = calloc(1, sizeof(*id));
     381           0 :                 if (!id) {
     382           0 :                         log_crit( _("Unable to allocate inode_with_dups structure\n"));
     383           0 :                         return META_ERROR;
     384             :                 }
     385           0 :                 id->block_no = ip->i_num.in_addr;
     386           0 :                 q = bitmap_type(ip->i_sbd, ip->i_num.in_addr);
     387             :                 /* If it's an invalid dinode, put it first on the invalid
     388             :                    inode reference list otherwise put it on the normal list. */
     389           0 :                 if (!inode_valid || q == GFS2_BLKST_UNLINKED)
     390           0 :                         osi_list_add_prev(&id->list, &dt->ref_invinode_list);
     391             :                 else {
     392             :                         /* If this is a system dinode, we want the duplicate
     393             :                            processing to find it first. That way references
     394             :                            from inside journals, et al, will take priority.
     395             :                            We don't want to delete journals in favor of dinodes
     396             :                            that reference a block inside a journal. */
     397           0 :                         if (fsck_system_inode(ip->i_sbd, id->block_no))
     398           0 :                                 osi_list_add(&id->list, &dt->ref_inode_list);
     399             :                         else
     400           0 :                                 osi_list_add_prev(&id->list,
     401             :                                                   &dt->ref_inode_list);
     402             :                 }
     403             :         }
     404           0 :         id->reftypecount[reftype]++;
     405           0 :         id->dup_count++;
     406           0 :         log_info(_("Found %d reference(s) to block %"PRIu64" (0x%"PRIx64") "
     407             :                    "as %s in %s inode #%"PRIu64" (0x%"PRIx64")\n"),
     408             :                   id->dup_count, block, block, reftypes[reftype],
     409             :                   inode_valid ? _("valid") : _("invalid"),
     410             :                   ip->i_num.in_addr, ip->i_num.in_addr);
     411           0 :         if (first)
     412           0 :                 log_info( _("This is the original reference.\n"));
     413             :         else {
     414             :                 /* Check for duplicate refs to the same block in one inode. */
     415           0 :                 if (id->dup_count > 1)
     416           0 :                         dt->dup_flags |= DUPFLAG_REF1_FOUND;
     417           0 :                 log_info( _("This brings the total to: %d inode references, "
     418             :                             "%d from this inode.\n"),
     419             :                           dt->refs, id->dup_count);
     420             :         }
     421           0 :         return META_IS_GOOD;
     422             : }
     423             : 
     424         224 : struct dir_info *dirtree_insert(struct fsck_cx *cx, struct lgfs2_inum inum)
     425             : {
     426         224 :         struct osi_node **newn = &cx->dirtree.osi_node, *parent = NULL;
     427             :         struct dir_info *data;
     428             : 
     429             :         /* Figure out where to put new node */
     430         504 :         while (*newn) {
     431         280 :                 struct dir_info *cur = (struct dir_info *)*newn;
     432             : 
     433         280 :                 parent = *newn;
     434         280 :                 if (inum.in_addr < cur->dinode.in_addr)
     435         112 :                         newn = &((*newn)->osi_left);
     436         168 :                 else if (inum.in_addr > cur->dinode.in_addr)
     437         168 :                         newn = &((*newn)->osi_right);
     438             :                 else
     439           0 :                         return cur;
     440             :         }
     441             : 
     442         224 :         data = calloc(1, sizeof(struct dir_info));
     443         224 :         if (!data) {
     444           0 :                 log_crit( _("Unable to allocate dir_info structure\n"));
     445           0 :                 return NULL;
     446             :         }
     447             :         /* Add new node and rebalance tree. */
     448         224 :         data->dinode.in_addr = inum.in_addr;
     449         224 :         data->dinode.in_formal_ino = inum.in_formal_ino;
     450         224 :         osi_link_node(&data->node, parent, newn);
     451         224 :         osi_insert_color(&data->node, &cx->dirtree);
     452             : 
     453         224 :         return data;
     454             : }
     455             : 
     456        3894 : struct dir_info *dirtree_find(struct fsck_cx *cx, uint64_t block)
     457             : {
     458        3894 :         struct osi_node *node = cx->dirtree.osi_node;
     459             : 
     460       10417 :         while (node) {
     461        8987 :                 struct dir_info *data = (struct dir_info *)node;
     462             : 
     463        8987 :                 if (block < data->dinode.in_addr)
     464        2998 :                         node = node->osi_left;
     465        5989 :                 else if (block > data->dinode.in_addr)
     466        3525 :                         node = node->osi_right;
     467             :                 else
     468        2464 :                         return data;
     469             :         }
     470        1430 :         return NULL;
     471             : }
     472             : 
     473             : /* get_ref_type - figure out if all duplicate references from this inode
     474             :    are the same type, and if so, return the type. */
     475           0 : enum dup_ref_type get_ref_type(struct inode_with_dups *id)
     476             : {
     477             :         enum dup_ref_type t, i;
     478             :         int found_type_with_ref;
     479             :         int found_other_types;
     480             : 
     481           0 :         for (t = REF_AS_DATA; t < REF_TYPES; t++) {
     482           0 :                 found_type_with_ref = 0;
     483           0 :                 found_other_types = 0;
     484           0 :                 for (i = REF_AS_DATA; i < REF_TYPES; i++) {
     485           0 :                         if (id->reftypecount[i]) {
     486           0 :                                 if (t == i)
     487           0 :                                         found_type_with_ref = 1;
     488             :                                 else
     489           0 :                                         found_other_types = 1;
     490             :                         }
     491             :                 }
     492           0 :                 if (found_type_with_ref)
     493           0 :                         return found_other_types ? REF_TYPES : t;
     494             :         }
     495           0 :         return REF_TYPES;
     496             : }
     497             : 
     498           0 : void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id)
     499             : {
     500           0 :         log_err(_("Removing duplicate reference to block %"PRIu64" (0x%"PRIx64") "
     501             :                   "referenced as %s by dinode %"PRIu64" (0x%"PRIx64")\n"),
     502             :                 dt->block, dt->block, reftypes[get_ref_type(id)], id->block_no, id->block_no);
     503           0 :         dt->refs--;
     504           0 :         if (id->name)
     505           0 :                 free(id->name);
     506           0 :         osi_list_del(&id->list);
     507           0 :         free(id);
     508           0 : }
     509             : 
     510           0 : void dup_delete(struct fsck_cx *cx, struct duptree *dt)
     511             : {
     512             :         struct inode_with_dups *id;
     513             :         osi_list_t *tmp;
     514             : 
     515           0 :         while (!osi_list_empty(&dt->ref_invinode_list)) {
     516           0 :                 tmp = (&dt->ref_invinode_list)->next;
     517           0 :                 id = osi_list_entry(tmp, struct inode_with_dups, list);
     518           0 :                 dup_listent_delete(dt, id);
     519             :         }
     520           0 :         while (!osi_list_empty(&dt->ref_inode_list)) {
     521           0 :                 tmp = (&dt->ref_inode_list)->next;
     522           0 :                 id = osi_list_entry(tmp, struct inode_with_dups, list);
     523           0 :                 dup_listent_delete(dt, id);
     524             :         }
     525           0 :         osi_erase(&dt->node, &cx->dup_blocks);
     526           0 :         free(dt);
     527           0 : }
     528             : 
     529         224 : void dirtree_delete(struct fsck_cx *cx, struct dir_info *b)
     530             : {
     531         224 :         osi_erase(&b->node, &cx->dirtree);
     532         224 :         free(b);
     533         224 : }
     534             : 
     535           0 : uint64_t find_free_blk(struct lgfs2_sbd *sdp)
     536             : {
     537           0 :         struct osi_node *n, *next = NULL;
     538           0 :         struct lgfs2_rgrp_tree *rl = NULL;
     539             :         struct gfs2_rgrp *rg;
     540           0 :         unsigned int block, bn = 0, x = 0, y = 0;
     541             :         unsigned int state;
     542             : 
     543           0 :         memset(&rg, 0, sizeof(rg));
     544           0 :         for (n = osi_first(&sdp->rgtree); n; n = next) {
     545           0 :                 next = osi_next(n);
     546           0 :                 rl = (struct lgfs2_rgrp_tree *)n;
     547           0 :                 if (rl->rt_free)
     548           0 :                         break;
     549             :         }
     550             : 
     551           0 :         if (n == NULL)
     552           0 :                 return 0;
     553             : 
     554           0 :         for (block = 0; block < rl->rt_length; block++) {
     555           0 :                 char *buf = rl->rt_bits[block].bi_data;
     556           0 :                 x = (block) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
     557             : 
     558           0 :                 for (; x < sdp->sd_bsize; x++)
     559           0 :                         for (y = 0; y < GFS2_NBBY; y++) {
     560           0 :                                 state = (buf[x] >> (GFS2_BIT_SIZE * y)) & 0x03;
     561           0 :                                 if (state == GFS2_BLKST_FREE)
     562           0 :                                         return rl->rt_data0 + bn;
     563           0 :                                 bn++;
     564             :                         }
     565             :         }
     566           0 :         return 0;
     567             : }
     568             : 
     569          29 : __be64 *get_dir_hash(struct lgfs2_inode *ip)
     570             : {
     571          29 :         unsigned hsize = (1 << ip->i_depth) * sizeof(uint64_t);
     572             :         int ret;
     573          29 :         __be64 *tbl = malloc(hsize);
     574             : 
     575          29 :         if (tbl == NULL)
     576           0 :                 return NULL;
     577             : 
     578          29 :         ret = lgfs2_readi(ip, tbl, 0, hsize);
     579          29 :         if (ret != hsize) {
     580           0 :                 free(tbl);
     581           0 :                 return NULL;
     582             :         }
     583             : 
     584          29 :         return tbl;
     585             : }
     586             : 
     587           1 : void delete_all_dups(struct fsck_cx *cx, struct lgfs2_inode *ip)
     588             : {
     589             :         struct osi_node *n, *next;
     590             :         struct duptree *dt;
     591             :         osi_list_t *tmp, *x;
     592             :         struct inode_with_dups *id;
     593             :         int found;
     594             : 
     595           1 :         for (n = osi_first(&cx->dup_blocks); n; n = next) {
     596           0 :                 next = osi_next(n);
     597           0 :                 dt = (struct duptree *)n;
     598             : 
     599           0 :                 found = 0;
     600           0 :                 id = NULL;
     601             : 
     602           0 :                 osi_list_foreach_safe(tmp, &dt->ref_invinode_list, x) {
     603           0 :                         id = osi_list_entry(tmp, struct inode_with_dups, list);
     604           0 :                         if (id->block_no == ip->i_num.in_addr) {
     605           0 :                                 dup_listent_delete(dt, id);
     606           0 :                                 found = 1;
     607             :                         }
     608             :                 }
     609           0 :                 osi_list_foreach_safe(tmp, &dt->ref_inode_list, x) {
     610           0 :                         id = osi_list_entry(tmp, struct inode_with_dups, list);
     611           0 :                         if (id->block_no == ip->i_num.in_addr) {
     612           0 :                                 dup_listent_delete(dt, id);
     613           0 :                                 found = 1;
     614             :                         }
     615             :                 }
     616           0 :                 if (!found)
     617           0 :                         continue;
     618             : 
     619           0 :                 if (dt->refs == 0) {
     620           0 :                         log_debug(_("This was the last reference: 0x%"PRIx64" is "
     621             :                                     "no longer a duplicate.\n"),
     622             :                                   dt->block);
     623           0 :                         dup_delete(cx, dt);
     624             :                 } else {
     625           0 :                         log_debug(_("%d references remain to 0x%"PRIx64"\n"),
     626             :                                   dt->refs, dt->block);
     627           0 :                         if (dt->refs > 1)
     628           0 :                                 continue;
     629             : 
     630           0 :                         id = NULL;
     631           0 :                         osi_list_foreach(tmp, &dt->ref_invinode_list)
     632           0 :                                 id = osi_list_entry(tmp,
     633             :                                                     struct inode_with_dups,
     634             :                                                     list);
     635           0 :                         osi_list_foreach(tmp, &dt->ref_inode_list)
     636           0 :                                 id = osi_list_entry(tmp,
     637             :                                                     struct inode_with_dups,
     638             :                                                     list);
     639           0 :                         if (id)
     640           0 :                                 log_debug("Last reference is from inode 0x%"PRIx64"\n",
     641             :                                           id->block_no);
     642             :                 }
     643             :         }
     644           1 : }
     645             : 
     646         392 : void print_pass_duration(const char *name, struct timeval *start)
     647             : {
     648         392 :         char duration[17] = ""; /* strlen("XXdXXhXXmXX.XXXs") + 1 */
     649             :         struct timeval end, diff;
     650             :         unsigned d, h, m, s;
     651         392 :         char *p = duration;
     652             : 
     653         392 :         gettimeofday(&end, NULL);
     654         392 :         timersub(&end, start, &diff);
     655             : 
     656         392 :         s = diff.tv_sec % 60;
     657         392 :         diff.tv_sec /= 60;
     658         392 :         m = diff.tv_sec % 60;
     659         392 :         diff.tv_sec /= 60;
     660         392 :         h = diff.tv_sec % 24;
     661         392 :         d = diff.tv_sec / 24;
     662             : 
     663         392 :         if (d)
     664           0 :                 p += snprintf(p, 4, "%ud", d > 99 ? 99U : d);
     665         392 :         if (h)
     666           0 :                 p += snprintf(p, 4, "%uh", h);
     667         392 :         if (m)
     668           0 :                 p += snprintf(p, 4, "%um", m);
     669             : 
     670         392 :         snprintf(p, 8, "%u.%03lus", s, diff.tv_usec / 1000);
     671         392 :         log_notice(_("%s completed in %s\n"), name, duration);
     672         392 : }
     673             : 

Generated by: LCOV version 1.14