LCOV - code coverage report
Current view: top level - fsck - util.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 22.9 % 349 80
Test Date: 2024-03-07 16:24:06 Functions: 42.1 % 19 8

            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    482744621 : 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    482744621 :         if (!one_percent)
      66           57 :                 one_percent = last_fs_block / 100;
      67    482744621 :         if (!last_reported_block ||
      68    482744621 :             block - last_reported_block >= one_percent) {
      69         5772 :                 last_reported_block = block;
      70         5772 :                 gettimeofday(&tv, NULL);
      71         5772 :                 if (!seconds)
      72           57 :                         seconds = tv.tv_sec;
      73         5772 :                 if (tv.tv_sec - seconds) {
      74              :                         static uint64_t percent;
      75              : 
      76            2 :                         seconds = tv.tv_sec;
      77            2 :                         if (last_fs_block) {
      78            2 :                                 percent = (block * 100) / last_fs_block;
      79            2 :                                 log_notice(_("\r%"PRIu64" percent complete.\r"), percent);
      80            2 :                                 fflush(stdout);
      81              :                         }
      82              :                 }
      83              :         }
      84    482744621 : }
      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          228 : struct dir_info *dirtree_insert(struct fsck_cx *cx, struct lgfs2_inum inum)
     425              : {
     426          228 :         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          513 :         while (*newn) {
     431          285 :                 struct dir_info *cur = (struct dir_info *)*newn;
     432              : 
     433          285 :                 parent = *newn;
     434          285 :                 if (inum.in_addr < cur->dinode.in_addr)
     435          114 :                         newn = &((*newn)->osi_left);
     436          171 :                 else if (inum.in_addr > cur->dinode.in_addr)
     437          171 :                         newn = &((*newn)->osi_right);
     438              :                 else
     439            0 :                         return cur;
     440              :         }
     441              : 
     442          228 :         data = calloc(1, sizeof(struct dir_info));
     443          228 :         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          228 :         data->dinode.in_addr = inum.in_addr;
     449          228 :         data->dinode.in_formal_ino = inum.in_formal_ino;
     450          228 :         osi_link_node(&data->node, parent, newn);
     451          228 :         osi_insert_color(&data->node, &cx->dirtree);
     452              : 
     453          228 :         return data;
     454              : }
     455              : 
     456         3962 : struct dir_info *dirtree_find(struct fsck_cx *cx, uint64_t block)
     457              : {
     458         3962 :         struct osi_node *node = cx->dirtree.osi_node;
     459              : 
     460        10597 :         while (node) {
     461         9143 :                 struct dir_info *data = (struct dir_info *)node;
     462              : 
     463         9143 :                 if (block < data->dinode.in_addr)
     464         3050 :                         node = node->osi_left;
     465         6093 :                 else if (block > data->dinode.in_addr)
     466         3585 :                         node = node->osi_right;
     467              :                 else
     468         2508 :                         return data;
     469              :         }
     470         1454 :         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          228 : void dirtree_delete(struct fsck_cx *cx, struct dir_info *b)
     530              : {
     531          228 :         osi_erase(&b->node, &cx->dirtree);
     532          228 :         free(b);
     533          228 : }
     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          399 : void print_pass_duration(const char *name, struct timeval *start)
     647              : {
     648          399 :         char duration[17] = ""; /* strlen("XXdXXhXXmXX.XXXs") + 1 */
     649              :         struct timeval end, diff;
     650              :         unsigned d, h, m, s;
     651          399 :         char *p = duration;
     652              : 
     653          399 :         gettimeofday(&end, NULL);
     654          399 :         timersub(&end, start, &diff);
     655              : 
     656          399 :         s = diff.tv_sec % 60;
     657          399 :         diff.tv_sec /= 60;
     658          399 :         m = diff.tv_sec % 60;
     659          399 :         diff.tv_sec /= 60;
     660          399 :         h = diff.tv_sec % 24;
     661          399 :         d = diff.tv_sec / 24;
     662              : 
     663          399 :         if (d)
     664            0 :                 p += snprintf(p, 4, "%ud", d > 99 ? 99U : d);
     665          399 :         if (h)
     666            0 :                 p += snprintf(p, 4, "%uh", h);
     667          399 :         if (m)
     668            0 :                 p += snprintf(p, 4, "%um", m);
     669              : 
     670          399 :         snprintf(p, 8, "%u.%03lus", s, diff.tv_usec / 1000);
     671          399 :         log_notice(_("%s completed in %s\n"), name, duration);
     672          399 : }
     673              : 
        

Generated by: LCOV version 2.0-1