LCOV - code coverage report
Current view: top level - fsck.ubifs - check_space.c (source / functions) Hit Total Coverage
Test: a simple test Lines: 285 316 90.2 %
Date: 2024-06-05 20:10:43 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2024, Huawei Technologies Co, Ltd.
       4             :  *
       5             :  * Authors: Zhihao Cheng <chengzhihao1@huawei.com>
       6             :  */
       7             : 
       8             : #include <stdio.h>
       9             : #include <stdlib.h>
      10             : 
      11             : #include "linux_err.h"
      12             : #include "bitops.h"
      13             : #include "kmem.h"
      14             : #include "ubifs.h"
      15             : #include "defs.h"
      16             : #include "debug.h"
      17             : #include "key.h"
      18             : #include "misc.h"
      19             : #include "fsck.ubifs.h"
      20             : 
      21             : /**
      22             :  * get_free_leb - get a free LEB according to @FSCK(c)->used_lebs.
      23             :  * @c: UBIFS file-system description object
      24             :  *
      25             :  * This function tries to find a free LEB, lnum is returned if found, otherwise
      26             :  * %-ENOSPC is returned.
      27             :  */
      28       19640 : int get_free_leb(struct ubifs_info *c)
      29             : {
      30             :         int lnum;
      31             : 
      32       39280 :         lnum = find_next_zero_bit(FSCK(c)->used_lebs, c->main_lebs, 0);
      33       19640 :         if (lnum >= c->main_lebs) {
      34           0 :                 ubifs_err(c, "No space left.");
      35             :                 return -ENOSPC;
      36             :         }
      37       39280 :         set_bit(lnum, FSCK(c)->used_lebs);
      38       19640 :         lnum += c->main_first;
      39             : 
      40       19640 :         return lnum;
      41             : }
      42             : 
      43             : /**
      44             :  * build_lpt - construct LPT and write it into flash.
      45             :  * @c: UBIFS file-system description object
      46             :  * @calculate_lp_cb: callback function to calculate the properties for given LEB
      47             :  * @free_ltab: %true means to release c->ltab after creating lpt
      48             :  *
      49             :  * This function builds LPT according to the calculated results by
      50             :  * @calculate_lp_cb and writes LPT into flash. Returns zero in case of success,
      51             :  * a negative error code in case of failure.
      52             :  */
      53         170 : int build_lpt(struct ubifs_info *c, calculate_lp_callback calculate_lp_cb,
      54             :               bool free_ltab)
      55             : {
      56             :         int i, err, lnum, free, dirty;
      57             :         u8 hash_lpt[UBIFS_HASH_ARR_SZ];
      58             : 
      59         170 :         memset(&c->lst, 0, sizeof(struct ubifs_lp_stats));
      60             :         /* Set gc lnum, equivalent to ubifs_rcvry_gc_commit/take_gc_lnum. */
      61         170 :         lnum = get_free_leb(c);
      62         170 :         if (lnum < 0)
      63             :                 return lnum;
      64         170 :         c->gc_lnum = lnum;
      65             : 
      66             :         /* Update LPT. */
      67      299008 :         for (i = 0; i < c->main_lebs; i++) {
      68      298838 :                 err = calculate_lp_cb(c, i, &free, &dirty, NULL);
      69      298838 :                 if (err)
      70             :                         return err;
      71             : 
      72      298838 :                 FSCK(c)->lpts[i].free = free;
      73      298838 :                 FSCK(c)->lpts[i].dirty = dirty;
      74      298838 :                 c->lst.total_free += free;
      75      298838 :                 c->lst.total_dirty += dirty;
      76             : 
      77      298838 :                 if (free == c->leb_size)
      78      139928 :                         c->lst.empty_lebs++;
      79             : 
      80      298838 :                 if (FSCK(c)->lpts[i].flags & LPROPS_INDEX) {
      81       19550 :                         c->lst.idx_lebs += 1;
      82             :                 } else {
      83             :                         int spc;
      84             : 
      85      279288 :                         spc = free + dirty;
      86      279288 :                         if (spc < c->dead_wm)
      87       13375 :                                 c->lst.total_dead += spc;
      88             :                         else
      89      265913 :                                 c->lst.total_dark += ubifs_calc_dark(c, spc);
      90      279288 :                         c->lst.total_used += c->leb_size - spc;
      91             :                 }
      92             : 
      93      298838 :                 dbg_fsck("build properties for LEB %d, free %d dirty %d is_idx %d, in %s",
      94             :                          i + c->main_first, free, dirty,
      95             :                          FSCK(c)->lpts[i].flags & LPROPS_INDEX ? 1 : 0,
      96             :                          c->dev_name);
      97             :         }
      98             : 
      99             :         /* Write LPT. */
     100         170 :         return ubifs_create_lpt(c, FSCK(c)->lpts, c->main_lebs, hash_lpt, free_ltab);
     101             : }
     102             : 
     103     6451333 : static int scan_get_lp(struct ubifs_info *c, int index, int *free, int *dirty,
     104             :                        int *is_idx)
     105             : {
     106             :         struct ubifs_scan_leb *sleb;
     107             :         struct ubifs_scan_node *snod;
     108     6451333 :         int used, idx_leb, lnum = index + c->main_first, err = 0;
     109     6451333 :         bool is_build_lpt = FSCK(c)->lpt_status & FR_LPT_CORRUPTED;
     110             : 
     111     6451333 :         if (is_build_lpt) {
     112        7868 :                 if (!test_bit(index, FSCK(c)->used_lebs) || c->gc_lnum == lnum) {
     113         370 :                         *free = c->leb_size;
     114         370 :                         *dirty = 0;
     115         370 :                         return 0;
     116             :                 }
     117             :         } else {
     118    12894798 :                 if (!test_bit(index, FSCK(c)->used_lebs)) {
     119     2268582 :                         *free = c->leb_size;
     120     2268582 :                         *dirty = 0;
     121     2268582 :                         return 0;
     122             :                 }
     123             :         }
     124             : 
     125     4182381 :         sleb = ubifs_scan(c, lnum, 0, c->sbuf, 0);
     126     4182381 :         if (IS_ERR(sleb)) {
     127             :                 /* All TNC LEBs have passed ubifs_scan in previous steps. */
     128           0 :                 ubifs_assert(c, !get_failure_reason_callback(c));
     129           0 :                 return PTR_ERR(sleb);
     130             :         }
     131             : 
     132     4182381 :         idx_leb = -1;
     133     4182381 :         used = 0;
     134  6325666510 :         list_for_each_entry(snod, &sleb->nodes, list) {
     135  6321484129 :                 int found, level = 0;
     136             : 
     137  6321484129 :                 if (idx_leb == -1)
     138     4182309 :                         idx_leb = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
     139             : 
     140  6321484129 :                 if (idx_leb)
     141             :                         /*
     142             :                          * Previous steps have ensured that every TNC LEB
     143             :                          * contains only index nodes or non-index nodes.
     144             :                          */
     145  2398717200 :                         ubifs_assert(c, snod->type == UBIFS_IDX_NODE);
     146             : 
     147  6321484129 :                 if (snod->type == UBIFS_IDX_NODE) {
     148  2398717200 :                         struct ubifs_idx_node *idx = snod->node;
     149             : 
     150  4797434400 :                         key_read(c, ubifs_idx_key(c, idx), &snod->key);
     151  2398717200 :                         level = le16_to_cpu(idx->level);
     152             :                 }
     153             : 
     154  6321484129 :                 found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
     155             :                                            snod->offs, idx_leb);
     156  6321484129 :                 if (found) {
     157  3051680531 :                         if (found < 0) {
     158           0 :                                 err = found;
     159             :                                 /*
     160             :                                  * TNC traversing is finished in previous steps,
     161             :                                  * any TNC path is accessible.
     162             :                                  */
     163           0 :                                 ubifs_assert(c, !get_failure_reason_callback(c));
     164             :                                 goto out;
     165             :                         }
     166  3051680531 :                         used += ALIGN(snod->len, 8);
     167             :                 }
     168             :         }
     169             : 
     170     4182381 :         if (is_build_lpt && !used) {
     171        1604 :                 *free = c->leb_size;
     172        1604 :                 *dirty = 0;
     173             :         } else {
     174     4180777 :                 *free = c->leb_size - sleb->endpt;
     175     4180777 :                 *dirty = sleb->endpt - used;
     176     4180777 :                 if (idx_leb == 1) {
     177     1466049 :                         if (is_build_lpt)
     178          82 :                                 FSCK(c)->lpts[index].flags = LPROPS_INDEX;
     179             :                         else
     180     1465967 :                                 *is_idx = 1;
     181             :                 }
     182             :         }
     183             : 
     184     6897109 : out:
     185     4182381 :         ubifs_scan_destroy(sleb);
     186     4182381 :         return err;
     187             : }
     188             : 
     189          95 : static void clear_buds(struct ubifs_info *c)
     190             : {
     191             :         int i;
     192             : 
     193             :         /*
     194             :          * Since lpt is invalid, space statistics cannot be trusted, the buds
     195             :          * were used to trace taken LEBs(LPT related), and fsck makes sure that
     196             :          * there will be no new journal writings(no space allocations) before
     197             :          * committing, so we should clear buds to prevent wrong lpt updating in
     198             :          * committing stage(eg. ubifs_return_leb operation for @c->old_buds).
     199             :          */
     200          95 :         free_buds(c, true);
     201         380 :         for (i = 0; i < c->jhead_cnt; i++) {
     202         285 :                 c->jheads[i].wbuf.lnum = -1;
     203         285 :                 c->jheads[i].wbuf.offs = -1;
     204             :         }
     205          95 : }
     206             : 
     207          95 : static void claer_lp_lists_and_heaps(struct ubifs_info *c)
     208             : {
     209             :         int i;
     210             : 
     211             :         /*
     212             :          * Since lpt is invalid, clear in-memory fast accessing paths (lp
     213             :          * lists & heaps).
     214             :          */
     215          95 :         c->freeable_cnt = 0;
     216          95 :         c->in_a_category_cnt = 0;
     217         380 :         for (i = 0; i < LPROPS_HEAP_CNT; i++) {
     218         285 :                 memset(c->lpt_heap[i].arr, 0, LPT_HEAP_SZ * sizeof(void *));
     219         285 :                 c->lpt_heap[i].cnt = 0;
     220         285 :                 c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
     221             :         }
     222          95 :         memset(c->dirty_idx.arr, 0, LPT_HEAP_SZ * sizeof(void *));
     223          95 :         c->dirty_idx.cnt = 0;
     224          95 :         c->dirty_idx.max_cnt = LPT_HEAP_SZ;
     225         190 :         INIT_LIST_HEAD(&c->uncat_list);
     226         190 :         INIT_LIST_HEAD(&c->empty_list);
     227         190 :         INIT_LIST_HEAD(&c->freeable_list);
     228         190 :         INIT_LIST_HEAD(&c->frdi_idx_list);
     229          95 : }
     230             : 
     231          95 : static int retake_ihead(struct ubifs_info *c)
     232             : {
     233          95 :         int err = take_ihead(c);
     234             : 
     235          95 :         if (err < 0) {
     236             :                 /* All LPT nodes must be accessible. */
     237           0 :                 ubifs_assert(c, !get_failure_reason_callback(c));
     238           0 :                 ubifs_assert(c, FSCK(c)->lpt_status == 0);
     239             :         } else
     240             :                 err = 0;
     241             : 
     242          95 :         return err;
     243             : }
     244             : 
     245          12 : static int rebuild_lpt(struct ubifs_info *c)
     246             : {
     247             :         int err;
     248             : 
     249             :         /* Clear buds. */
     250          12 :         clear_buds(c);
     251             :         /* Clear stale in-memory lpt data. */
     252          12 :         c->lpt_drty_flgs = 0;
     253          12 :         c->dirty_nn_cnt = 0;
     254          12 :         c->dirty_pn_cnt = 0;
     255          12 :         claer_lp_lists_and_heaps(c);
     256          12 :         ubifs_free_lpt_nodes(c);
     257          24 :         kfree(c->ltab);
     258          12 :         c->ltab = NULL;
     259             : 
     260          24 :         FSCK(c)->lpts = kzalloc(sizeof(struct ubifs_lprops) * c->main_lebs,
     261             :                                 GFP_KERNEL);
     262          12 :         if (!FSCK(c)->lpts) {
     263           0 :                 log_err(c, errno, "can not allocate lpts");
     264           0 :                 return -ENOMEM;
     265             :         }
     266             : 
     267          12 :         err = build_lpt(c, scan_get_lp, false);
     268          12 :         if (err)
     269             :                 goto out;
     270             : 
     271          12 :         err = retake_ihead(c);
     272          12 :         if (err)
     273             :                 goto out;
     274             : 
     275          12 :         FSCK(c)->lpt_status = 0;
     276             : 
     277          12 : out:
     278          24 :         kfree(FSCK(c)->lpts);
     279          12 :         return err;
     280             : }
     281             : 
     282     2688428 : static void check_and_correct_nnode(struct ubifs_info *c,
     283             :                                     struct ubifs_nnode *nnode,
     284             :                                     struct ubifs_nnode *parent_nnode,
     285             :                                     int row, int col, int *corrected)
     286             : {
     287     2688428 :         int num = ubifs_calc_nnode_num(row, col);
     288             : 
     289     2688428 :         if (nnode->num != num) {
     290           0 :                 struct nnode_problem nnp = {
     291             :                         .nnode = nnode,
     292             :                         .parent_nnode = parent_nnode,
     293             :                         .num = num,
     294             :                 };
     295             : 
     296             :                 /*
     297             :                  * The nnode number is read from disk in big lpt mode, which
     298             :                  * could lead to the wrong nnode number, otherwise, ther nnode
     299             :                  * number cannot be wrong.
     300             :                  */
     301           0 :                 ubifs_assert(c, c->big_lpt);
     302           0 :                 FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     303           0 :                 if (fix_problem(c, NNODE_INCORRECT, &nnp)) {
     304           0 :                         nnode->num = num;
     305           0 :                         *corrected = 1;
     306             :                 }
     307             :         }
     308     2688428 : }
     309             : 
     310     1612197 : static int check_and_correct_pnode(struct ubifs_info *c,
     311             :                                    struct ubifs_pnode *pnode, int col,
     312             :                                    struct ubifs_lp_stats *lst,
     313             :                                    int *freeable_cnt, int *corrected)
     314             : {
     315             :         int i, index, lnum;
     316     1612197 :         const int lp_cnt = UBIFS_LPT_FANOUT;
     317             : 
     318     1612197 :         if (pnode->num != col) {
     319           0 :                 struct pnode_problem pnp = {
     320             :                         .pnode = pnode,
     321             :                         .num = col,
     322             :                 };
     323             : 
     324             :                 /*
     325             :                  * The pnode number is read from disk in big lpt mode, which
     326             :                  * could lead to the wrong pnode number, otherwise, ther pnode
     327             :                  * number cannot be wrong.
     328             :                  */
     329           0 :                 ubifs_assert(c, c->big_lpt);
     330           0 :                 FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     331           0 :                 if (fix_problem(c, PNODE_INCORRECT, &pnp)) {
     332           0 :                         pnode->num = col;
     333           0 :                         *corrected = 1;
     334             :                 }
     335             :         }
     336             : 
     337     1612197 :         index = pnode->num << UBIFS_LPT_FANOUT_SHIFT;
     338     1612197 :         lnum = index + c->main_first;
     339     8059596 :         for (i = 0; i < lp_cnt && lnum < c->leb_cnt; i++, index++, lnum++) {
     340     6447399 :                 int err, cat, free, dirty, is_idx = 0;
     341     6447399 :                 struct ubifs_lprops *lp = &pnode->lprops[i];
     342             : 
     343     6447399 :                 err = scan_get_lp(c, index, &free, &dirty, &is_idx);
     344     6447399 :                 if (err)
     345           0 :                         return err;
     346             : 
     347     6447399 :                 dbg_fsck("calculate properties for LEB %d, free %d dirty %d is_idx %d, in %s",
     348             :                          lnum, free, dirty, is_idx, c->dev_name);
     349             : 
     350     6447399 :                 if (!FSCK(c)->lpt_status && lp->free + lp->dirty == c->leb_size
     351     4405280 :                     && !test_bit(index, FSCK(c)->used_lebs)) {
     352             :                         /*
     353             :                          * Some LEBs may become freeable in the following cases:
     354             :                          *  a. LEBs become freeable after replaying the journal.
     355             :                          *  b. Unclean reboot while doing gc for a freeable
     356             :                          *     non-index LEB
     357             :                          *  c. Freeable index LEBs in an uncompleted commit due
     358             :                          *     to an unclean unmount.
     359             :                          * , which makes that these LEBs won't be accounted into
     360             :                          * the FSCK(c)->used_lebs, but they actually have
     361             :                          * free/dirty space statistics. So we should skip
     362             :                          * checking space for these LEBs.
     363             :                          */
     364     2202560 :                         free = lp->free;
     365     2202560 :                         dirty = lp->dirty;
     366     2202560 :                         is_idx = (lp->flags & LPROPS_INDEX) ? 1 : 0;
     367             :                 }
     368    12894798 :                 if (lnum != lp->lnum ||
     369    19340810 :                     free != lp->free || dirty != lp->dirty ||
     370     7912307 :                     (is_idx && !(lp->flags & LPROPS_INDEX)) ||
     371     4980965 :                     (!is_idx && (lp->flags & LPROPS_INDEX))) {
     372         766 :                         struct lp_problem lpp = {
     373             :                                 .lnum = lnum,
     374             :                                 .lp = lp,
     375             :                                 .free = free,
     376             :                                 .dirty = dirty,
     377             :                                 .is_idx = is_idx,
     378             :                         };
     379             : 
     380         766 :                         FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     381         766 :                         if (fix_problem(c, LP_INCORRECT, &lpp)) {
     382         766 :                                 lp->lnum = lnum;
     383         766 :                                 lp->free = free;
     384         766 :                                 lp->dirty = dirty;
     385         766 :                                 lp->flags = is_idx ? LPROPS_INDEX : 0;
     386         766 :                                 *corrected = 1;
     387             :                         }
     388             :                 }
     389             : 
     390     6447399 :                 cat = ubifs_categorize_lprops(c, lp);
     391     6447399 :                 if (cat != (lp->flags & LPROPS_CAT_MASK)) {
     392     3610513 :                         if (FSCK(c)->lpt_status & FR_LPT_INCORRECT) {
     393       61304 :                                 lp->flags |= cat;
     394             :                         } else {
     395             :                                 /* lp could be in the heap or un-categorized(add heap failed). */
     396     3549209 :                                 ubifs_assert(c, (lp->flags & LPROPS_CAT_MASK) == LPROPS_UNCAT);
     397             :                         }
     398             :                 }
     399     6447399 :                 if (cat == LPROPS_FREEABLE)
     400        1774 :                         *freeable_cnt = *freeable_cnt + 1;
     401     6447399 :                 if ((lp->flags & LPROPS_TAKEN) && free == c->leb_size)
     402          24 :                         lst->taken_empty_lebs += 1;
     403             : 
     404     6447399 :                 lst->total_free += free;
     405     6447399 :                 lst->total_dirty += dirty;
     406             : 
     407     6447399 :                 if (free == c->leb_size)
     408     2266676 :                         lst->empty_lebs++;
     409             : 
     410     6447399 :                 if (is_idx) {
     411     1465981 :                         lst->idx_lebs += 1;
     412             :                 } else {
     413             :                         int spc;
     414             : 
     415     4981418 :                         spc = free + dirty;
     416     4981418 :                         if (spc < c->dead_wm)
     417      182807 :                                 lst->total_dead += spc;
     418             :                         else
     419     4798611 :                                 lst->total_dark += ubifs_calc_dark(c, spc);
     420     4981418 :                         lst->total_used += c->leb_size - spc;
     421             :                 }
     422             :         }
     423             : 
     424             :         return 0;
     425             : }
     426             : 
     427        1519 : static int check_and_correct_lpt(struct ubifs_info *c, int *lpt_corrected)
     428             : {
     429             :         int err, i, cnt, iip, row, col, corrected, lnum, max_num, freeable_cnt;
     430             :         struct ubifs_cnode *cn, *cnode;
     431             :         struct ubifs_nnode *nnode, *nn;
     432             :         struct ubifs_pnode *pnode;
     433             :         struct ubifs_lp_stats lst;
     434             : 
     435        1519 :         max_num = 0;
     436        1519 :         freeable_cnt = 0;
     437        1519 :         memset(&lst, 0, sizeof(struct ubifs_lp_stats));
     438             : 
     439             :         /* Load the entire LPT tree, check whether there are corrupted nodes. */
     440        1519 :         cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
     441     1614188 :         for (i = 0; i < cnt; i++) {
     442     1612669 :                 pnode = ubifs_pnode_lookup(c, i);
     443     1612669 :                 if (IS_ERR(pnode))
     444           0 :                         return PTR_ERR(pnode);
     445     1612669 :                 if (pnode->num > max_num)
     446     1611150 :                         max_num = pnode->num;
     447             :         }
     448             : 
     449             :         /* Check whether there are pnodes exceeding the 'c->main_lebs'. */
     450        1519 :         pnode = ubifs_pnode_lookup(c, 0);
     451        1519 :         if (IS_ERR(pnode))
     452           0 :                 return PTR_ERR(pnode);
     453     1551672 :         while (pnode) {
     454     1550157 :                 if (pnode->num > max_num) {
     455           0 :                         ubifs_err(c, "pnode(%d) exceeds max number(%d)",
     456             :                                   pnode->num, max_num);
     457             :                         set_failure_reason_callback(c, FR_LPT_CORRUPTED);
     458             :                         return -EINVAL;
     459             :                 }
     460     1550157 :                 pnode = ubifs_find_next_pnode(c, pnode);
     461     1550157 :                 if (IS_ERR(pnode))
     462           4 :                         return PTR_ERR(pnode);
     463             :         }
     464             : 
     465             :         /* Check & correct nnodes and pnodes(including LEB properties). */
     466        1515 :         row = col = iip = 0;
     467        1515 :         cnode = (struct ubifs_cnode *)c->nroot;
     468     4303655 :         while (cnode) {
     469     4300625 :                 ubifs_assert(c, row >= 0);
     470     4300625 :                 nnode = cnode->parent;
     471     4300625 :                 if (cnode->level) {
     472     2688428 :                         corrected = 0;
     473             :                         /* cnode is a nnode */
     474     2688428 :                         nn = (struct ubifs_nnode *)cnode;
     475     2688428 :                         check_and_correct_nnode(c, nn, nnode, row, col,
     476             :                                                 &corrected);
     477     2688428 :                         if (corrected)
     478           0 :                                 ubifs_make_nnode_dirty(c, nn);
     479     2694365 :                         while (iip < UBIFS_LPT_FANOUT) {
     480     2155492 :                                 cn = nn->nbranch[iip].cnode;
     481     2155492 :                                 if (cn) {
     482             :                                         /* Go down */
     483     2149555 :                                         row += 1;
     484     2149555 :                                         col <<= UBIFS_LPT_FANOUT_SHIFT;
     485     2149555 :                                         col += iip;
     486     2149555 :                                         iip = 0;
     487     2149555 :                                         cnode = cn;
     488     2149555 :                                         break;
     489             :                                 }
     490             :                                 /* Go right */
     491        5937 :                                 iip += 1;
     492             :                         }
     493     2688428 :                         if (iip < UBIFS_LPT_FANOUT)
     494     2149555 :                                 continue;
     495             :                 } else {
     496     1612197 :                         corrected = 0;
     497             :                         /* cnode is a pnode */
     498     1612197 :                         pnode = (struct ubifs_pnode *)cnode;
     499     1612197 :                         err = check_and_correct_pnode(c, pnode, col, &lst,
     500             :                                                       &freeable_cnt, &corrected);
     501     1612197 :                         if (err)
     502             :                                 return err;
     503     1612197 :                         if (corrected)
     504         601 :                                 ubifs_make_pnode_dirty(c, pnode);
     505             :                 }
     506             :                 /* Go up and to the right */
     507     2151070 :                 row -= 1;
     508     2151070 :                 col >>= UBIFS_LPT_FANOUT_SHIFT;
     509     2151070 :                 iip = cnode->iip + 1;
     510     2151070 :                 cnode = (struct ubifs_cnode *)nnode;
     511             :         }
     512             : 
     513        1515 :         dbg_fsck("empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld,"
     514             :                  " total_used %lld, total_dead %lld, total_dark %lld,"
     515             :                  " taken_empty_lebs %d, freeable_cnt %d, in %s",
     516             :                  lst.empty_lebs, lst.idx_lebs, lst.total_free, lst.total_dirty,
     517             :                  lst.total_used, lst.total_dead, lst.total_dark,
     518             :                  lst.taken_empty_lebs, freeable_cnt, c->dev_name);
     519             : 
     520             :         /* Check & correct the global space statistics. */
     521        2968 :         if (lst.empty_lebs != c->lst.empty_lebs ||
     522        2906 :             lst.idx_lebs != c->lst.idx_lebs ||
     523        2899 :             lst.total_free != c->lst.total_free ||
     524        2887 :             lst.total_dirty != c->lst.total_dirty ||
     525        2882 :             lst.total_used != c->lst.total_used ||
     526        2879 :             lst.total_dead != c->lst.total_dead ||
     527        1438 :             lst.total_dark != c->lst.total_dark) {
     528          77 :                 struct space_stat_problem ssp = {
     529          77 :                         .lst = &c->lst,
     530             :                         .calc_lst = &lst,
     531             :                 };
     532             : 
     533          77 :                 FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     534          77 :                 if (fix_problem(c, SPACE_STAT_INCORRECT, &ssp)) {
     535          77 :                         c->lst.empty_lebs = lst.empty_lebs;
     536          77 :                         c->lst.idx_lebs = lst.idx_lebs;
     537          77 :                         c->lst.total_free = lst.total_free;
     538          77 :                         c->lst.total_dirty = lst.total_dirty;
     539          77 :                         c->lst.total_used = lst.total_used;
     540          77 :                         c->lst.total_dead = lst.total_dead;
     541          77 :                         c->lst.total_dark = lst.total_dark;
     542             :                 }
     543             :         }
     544             : 
     545             :         /* Check & correct the lprops table information. */
     546        4593 :         for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
     547        3078 :                 err = dbg_check_ltab_lnum(c, lnum);
     548        3078 :                 if (err)
     549             :                         return err;
     550             :         }
     551             : 
     552        1515 :         if (FSCK(c)->lpt_status & FR_LPT_INCORRECT) {
     553          83 :                 c->lst.taken_empty_lebs = 0;
     554             :                 /* Clear buds. */
     555          83 :                 clear_buds(c);
     556             :                 /* Clear lp lists & heaps. */
     557          83 :                 claer_lp_lists_and_heaps(c);
     558             :                 /*
     559             :                  * Build lp lists & heaps, subsequent steps could recover
     560             :                  * disconnected files by allocating free space.
     561             :                  */
     562      274405 :                 for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
     563             :                         int cat;
     564      274322 :                         struct ubifs_lprops *lp = ubifs_lpt_lookup(c, lnum);
     565      274322 :                         if (IS_ERR(lp))
     566           0 :                                 return PTR_ERR(lp);
     567             : 
     568      274322 :                         cat = lp->flags & LPROPS_CAT_MASK;
     569      274322 :                         ubifs_add_to_cat(c, lp, cat);
     570             :                 }
     571             :                 /*
     572             :                  * The %LPROPS_TAKEN flag is cleared in LEB properties, just
     573             :                  * remark it.
     574             :                  */
     575          83 :                 err = retake_ihead(c);
     576          83 :                 if (err)
     577             :                         return err;
     578             : 
     579          83 :                 *lpt_corrected = 1;
     580          83 :                 FSCK(c)->lpt_status &= ~FR_LPT_INCORRECT;
     581             :         } else {
     582        1432 :                 ubifs_assert(c, c->freeable_cnt == freeable_cnt);
     583        1432 :                 ubifs_assert(c, c->lst.taken_empty_lebs == lst.taken_empty_lebs);
     584        1432 :                 ubifs_assert(c, c->in_a_category_cnt == c->main_lebs);
     585             :         }
     586             : 
     587             :         return 0;
     588             : }
     589             : 
     590             : /**
     591             :  * check_and_correct_space - check & correct the space statistics.
     592             :  * @c: UBIFS file-system description object
     593             :  *
     594             :  * This function does following things:
     595             :  * 1. Check fsck mode, exit program if current mode is check mode.
     596             :  * 2. Check space statistics by comparing lpt records with scanning results
     597             :  *    for all main LEBs. There could be following problems:
     598             :  *    a) comparison result is inconsistent: correct the lpt records by LEB
     599             :  *       scanning results.
     600             :  *    b) lpt is corrupted: rebuild lpt.
     601             :  * 3. Set the gc lnum.
     602             :  * Returns zero in case of success, a negative error code in case of failure.
     603             :  */
     604        1547 : int check_and_correct_space(struct ubifs_info *c)
     605             : {
     606        1547 :         int err, lpt_corrected = 0;
     607             : 
     608        1547 :         if (FSCK(c)->mode == CHECK_MODE) {
     609             :                 /*
     610             :                  * The check mode will exit, because unclean LEBs are not
     611             :                  * rewritten for readonly mode in previous steps.
     612             :                  */
     613          20 :                 if (FSCK(c)->lpt_status)
     614           0 :                         exit_code |= FSCK_UNCORRECTED;
     615          20 :                 dbg_fsck("skip checking & correcting space%s, in %s",
     616             :                          mode_name(c), c->dev_name);
     617          20 :                 exit(exit_code);
     618             :         }
     619             : 
     620        1527 :         log_out(c, "Check and correct the space statistics");
     621             : 
     622        1527 :         if (FSCK(c)->lpt_status & FR_LPT_CORRUPTED) {
     623          12 : rebuild:
     624          12 :                 if (fix_problem(c, LPT_CORRUPTED, NULL))
     625          12 :                         return rebuild_lpt(c);
     626             :         }
     627             : 
     628        1519 :         err = check_and_correct_lpt(c, &lpt_corrected);
     629        1519 :         if (err) {
     630           4 :                 if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED))
     631             :                         goto rebuild;
     632             :                 return err;
     633             :         }
     634             : 
     635             :         /* Set gc lnum. */
     636        1515 :         if (c->need_recovery || lpt_corrected) {
     637         537 :                 err = ubifs_rcvry_gc_commit(c);
     638         537 :                 if (err) {
     639             :                         /* All LPT nodes must be accessible. */
     640          28 :                         ubifs_assert(c, !get_failure_reason_callback(c));
     641          28 :                         ubifs_assert(c, FSCK(c)->lpt_status == 0);
     642             :                         return err;
     643             :                 }
     644             :         } else {
     645         978 :                 err = take_gc_lnum(c);
     646         978 :                 if (err) {
     647             :                         /* All LPT nodes must be accessible. */
     648           0 :                         ubifs_assert(c, !get_failure_reason_callback(c));
     649           0 :                         ubifs_assert(c, FSCK(c)->lpt_status == 0);
     650             :                         return err;
     651             :                 }
     652         978 :                 err = ubifs_leb_unmap(c, c->gc_lnum);
     653             :                 if (err)
     654             :                         return err;
     655             :         }
     656             : 
     657             :         return err;
     658             : }
     659             : 
     660             : /**
     661             :  * check_and_correct_index_size - check & correct the index size.
     662             :  * @c: UBIFS file-system description object
     663             :  *
     664             :  * This function checks and corrects the index size by traversing TNC: Returns
     665             :  * zero in case of success, a negative error code in case of failure.
     666             :  */
     667        1497 : int check_and_correct_index_size(struct ubifs_info *c)
     668             : {
     669             :         int err;
     670        1497 :         unsigned long long index_size = 0;
     671             : 
     672        1497 :         ubifs_assert(c, c->bi.old_idx_sz == c->calc_idx_sz);
     673        1497 :         err = dbg_walk_index(c, NULL, add_size, &index_size);
     674        1497 :         if (err) {
     675             :                 /* All TNC nodes must be accessible. */
     676           0 :                 ubifs_assert(c, !get_failure_reason_callback(c));
     677             :                 return err;
     678             :         }
     679             : 
     680        1497 :         dbg_fsck("total index size %llu, in %s", index_size, c->dev_name);
     681        1500 :         if (index_size != c->calc_idx_sz &&
     682           3 :             fix_problem(c, INCORRECT_IDX_SZ, &index_size))
     683           3 :                 c->bi.old_idx_sz = c->calc_idx_sz = index_size;
     684             : 
     685             :         return 0;
     686             : }

Generated by: LCOV version 1.13