LCOV - code coverage report
Current view: top level - fsck.ubifs - fsck.ubifs.c (source / functions) Hit Total Coverage
Test: a simple test Lines: 257 320 80.3 %
Date: 2024-06-05 20:10:43 Functions: 17 18 94.4 %
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             : #include <getopt.h>
      11             : #include <signal.h>
      12             : 
      13             : #include "bitops.h"
      14             : #include "kmem.h"
      15             : #include "ubifs.h"
      16             : #include "defs.h"
      17             : #include "debug.h"
      18             : #include "key.h"
      19             : #include "misc.h"
      20             : #include "fsck.ubifs.h"
      21             : 
      22             : /*
      23             :  * Because we copy functions from the kernel, we use a subset of the UBIFS
      24             :  * file-system description object struct ubifs_info.
      25             :  */
      26             : struct ubifs_info info_;
      27             : static struct ubifs_info *c = &info_;
      28             : 
      29             : int exit_code = FSCK_OK;
      30             : 
      31             : static const char *optstring = "Vrg:abyn";
      32             : 
      33             : static const struct option longopts[] = {
      34             :         {"version",            0, NULL, 'V'},
      35             :         {"reserve",            1, NULL, 'r'},
      36             :         {"debug",              1, NULL, 'g'},
      37             :         {"auto",               1, NULL, 'a'},
      38             :         {"rebuild",            1, NULL, 'b'},
      39             :         {"yes",                1, NULL, 'y'},
      40             :         {"nochange",           1, NULL, 'n'},
      41             :         {NULL, 0, NULL, 0}
      42             : };
      43             : 
      44             : static const char *helptext =
      45             : "Usage: fsck.ubifs [OPTIONS] ubi_volume\n"
      46             : "Check & repair UBIFS filesystem on a given UBI volume\n\n"
      47             : "Options:\n"
      48             : "-V, --version            Display version information\n"
      49             : "-g, --debug=LEVEL        Display debug information (0 - none, 1 - error message,\n"
      50             : "                         2 - warning message[default], 3 - notice message, 4 - debug message)\n"
      51             : "-a, --auto               Automatic safely repair without droping data (No questions).\n"
      52             : "                         Can not be specified at the same time as the -y or -n options\n"
      53             : "-y, --yes                Assume \"yes\" to all questions. Automatic repair and report dropping data (No questions).\n"
      54             : "                         There are two submodes for this working mode:\n"
      55             : "                           a. default - Fail if TNC/master/log is corrupted. Only -y option is specified\n"
      56             : "                           b. rebuild fs - Turn to rebuild fs if TNC/master/log is corrupted. Specify -b option to make effect\n"
      57             : "                         Can not be specified at the same time as the -a or -n options\n"
      58             : "-b, --rebuild            Forcedly repair the filesystem even by rebuilding filesystem.\n"
      59             : "                         Depends on -y option\n"
      60             : "-n, --nochange           Make no changes to the filesystem, only check filesystem.\n"
      61             : "                         This mode don't check space, because unclean LEBs are not rewritten in readonly mode.\n"
      62             : "                         Can not be specified at the same time as the -a or -y options\n"
      63             : "Examples:\n"
      64             : "\t1. Check and repair filesystem from UBI volume /dev/ubi0_0\n"
      65             : "\t   fsck.ubifs /dev/ubi0_0\n"
      66             : "\t2. Only check without modifying filesystem from UBI volume /dev/ubi0_0\n"
      67             : "\t   fsck.ubifs -n /dev/ubi0_0\n"
      68             : "\t3. Check and safely repair filesystem from UBI volume /dev/ubi0_0\n"
      69             : "\t   fsck.ubifs -a /dev/ubi0_0\n"
      70             : "\t4. Check and forcedly repair filesystem from UBI volume /dev/ubi0_0\n"
      71             : "\t   fsck.ubifs -y -b /dev/ubi0_0\n\n";
      72             : 
      73          24 : static inline void usage(void)
      74             : {
      75          24 :         printf("%s", helptext);
      76          24 :         exit_code |= FSCK_USAGE;
      77          24 :         exit(exit_code);
      78             : }
      79             : 
      80        2519 : static void get_options(int argc, char* argv[], int *mode)
      81             : {
      82        2519 :         int opt, i, submode = 0;
      83             :         char *endp;
      84             : 
      85             :         while (1) {
      86        6509 :                 opt = getopt_long(argc, argv, optstring, longopts, &i);
      87        6509 :                 if (opt == -1)
      88             :                         break;
      89        4007 :                 switch (opt) {
      90           1 :                 case 'V':
      91           1 :                         common_print_version();
      92           1 :                         exit(FSCK_OK);
      93         274 :                 case 'g':
      94         274 :                         c->debug_level = strtol(optarg, &endp, 0);
      95         274 :                         if (*endp != '\0' || endp == optarg ||
      96         274 :                             c->debug_level < 0 || c->debug_level > DEBUG_LEVEL) {
      97           4 :                                 log_err(c, 0, "bad debugging level '%s'", optarg);
      98           2 :                                 usage();
      99             :                         }
     100             :                         break;
     101         961 :                 case 'a':
     102         961 :                         if (*mode != NORMAL_MODE) {
     103           6 :                         conflict_opt:
     104          12 :                                 log_err(c, 0, "Only one of the options -a, -n or -y may be specified");
     105           6 :                                 usage();
     106             :                         }
     107         961 :                         *mode = SAFE_MODE;
     108         961 :                         break;
     109        1387 :                 case 'y':
     110        1387 :                         if (*mode != NORMAL_MODE)
     111             :                                 goto conflict_opt;
     112        1383 :                         *mode = DANGER_MODE0;
     113        1383 :                         break;
     114        1224 :                 case 'b':
     115        1224 :                         submode = 1;
     116        1224 :                         break;
     117         148 :                 case 'n':
     118         148 :                         if (*mode != NORMAL_MODE)
     119             :                                 goto conflict_opt;
     120         146 :                         *mode = CHECK_MODE;
     121         146 :                         c->ro_mount = 1;
     122         146 :                         break;
     123             :                 case 'r':
     124             :                         /* Compatible with FSCK(8). */
     125             :                         break;
     126           8 :                 default:
     127           8 :                         usage();
     128             :                 }
     129             :         }
     130             : 
     131        2502 :         if (submode) {
     132        1224 :                 if (*mode != DANGER_MODE0) {
     133           4 :                         log_err(c, 0, "Option -y is not specified when -b is used");
     134           2 :                         usage();
     135             :                 } else
     136        1222 :                         *mode = DANGER_MODE1;
     137             :         }
     138             : 
     139        2500 :         if (optind != argc) {
     140        2494 :                 c->dev_name = strdup(argv[optind]);
     141        2494 :                 if (!c->dev_name) {
     142           0 :                         log_err(c, errno, "can not allocate dev_name");
     143           0 :                         exit_code |= FSCK_ERROR;
     144           0 :                         exit(exit_code);
     145             :                 }
     146             :         }
     147             : 
     148        2500 :         if (!c->dev_name) {
     149          12 :                 log_err(c, 0, "no ubi_volume specified");
     150           6 :                 usage();
     151             :         }
     152        2494 : }
     153             : 
     154        2519 : static void exit_callback(void)
     155             : {
     156        2519 :         if (exit_code & FSCK_NONDESTRUCT)
     157        1264 :                 log_out(c, "********** Filesystem was modified **********");
     158        2519 :         if (exit_code & FSCK_UNCORRECTED)
     159         700 :                 log_out(c, "********** WARNING: Filesystem still has errors **********");
     160        2519 :         if (exit_code & ~(FSCK_OK|FSCK_NONDESTRUCT))
     161        1686 :                 log_out(c, "FSCK failed, exit code %d", exit_code);
     162             :         else
     163        3352 :                 log_out(c, "FSCK success!");
     164        2519 : }
     165             : 
     166           0 : static void fsck_assert_failed(__unused const struct ubifs_info *c)
     167             : {
     168           0 :         exit_code |= FSCK_ERROR;
     169           0 :         exit(exit_code);
     170             : }
     171             : 
     172      190794 : static void fsck_set_failure_reason(const struct ubifs_info *c,
     173             :                                     unsigned int reason)
     174             : {
     175      190794 :         if (FSCK(c)->mode == REBUILD_MODE)
     176             :                 return;
     177             : 
     178      186598 :         FSCK(c)->failure_reason = reason;
     179      186598 :         if (reason & FR_LPT_CORRUPTED) {
     180          66 :                 log_out(c, "Found corrupted pnode/nnode, set lpt corrupted");
     181          66 :                 FSCK(c)->lpt_status |= FR_LPT_CORRUPTED;
     182             :         }
     183      186598 :         if (reason & FR_LPT_INCORRECT) {
     184           9 :                 log_out(c, "Bad space statistics, set lpt incorrect");
     185           9 :                 FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     186             :         }
     187             : }
     188             : 
     189         794 : static unsigned int fsck_get_failure_reason(const struct ubifs_info *c)
     190             : {
     191         794 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     192             : 
     193         794 :         return FSCK(c)->failure_reason;
     194             : }
     195             : 
     196         570 : static void fsck_clear_failure_reason(const struct ubifs_info *c)
     197             : {
     198         570 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     199             : 
     200         570 :         FSCK(c)->failure_reason = 0;
     201         570 : }
     202             : 
     203      186036 : static bool fsck_test_and_clear_failure_reason(const struct ubifs_info *c,
     204             :                                                unsigned int reason)
     205             : {
     206      186036 :         bool res = (FSCK(c)->failure_reason & reason) != 0;
     207             : 
     208      186036 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     209      186036 :         ubifs_assert(c, !(FSCK(c)->failure_reason & (~reason)));
     210             : 
     211      186036 :         FSCK(c)->failure_reason = 0;
     212             : 
     213      186036 :         return res;
     214             : }
     215             : 
     216           7 : static void fsck_set_lpt_invalid(const struct ubifs_info *c,
     217             :                                  unsigned int reason)
     218             : {
     219           7 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     220             : 
     221           7 :         if (reason & FR_LPT_CORRUPTED) {
     222           0 :                 log_out(c, "Found corrupted pnode/nnode, set lpt corrupted");
     223           0 :                 FSCK(c)->lpt_status |= FR_LPT_CORRUPTED;
     224             :         }
     225           7 :         if (reason & FR_LPT_INCORRECT) {
     226           7 :                 log_out(c, "Bad space statistics, set lpt incorrect");
     227           7 :                 FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     228             :         }
     229           7 : }
     230             : 
     231    11625442 : static bool fsck_test_lpt_valid(const struct ubifs_info *c, int lnum,
     232             :                                 int old_free, int old_dirty,
     233             :                                 int free, int dirty)
     234             : {
     235    11625442 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     236             : 
     237    11625442 :         if (c->cmt_state != COMMIT_RESTING)
     238             :                 /* Don't skip updating lpt when do commit. */
     239             :                 goto out;
     240             : 
     241    11613406 :         if (FSCK(c)->lpt_status)
     242             :                 return false;
     243             : 
     244    11549750 :         if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs) {
     245           0 :                 log_out(c, "Bad empty_lebs %d(main_lebs %d), set lpt incorrect",
     246             :                         c->lst.empty_lebs, c->main_lebs);
     247           0 :                 goto out_invalid;
     248             :         }
     249    11549750 :         if (c->freeable_cnt < 0 || c->freeable_cnt > c->main_lebs) {
     250           0 :                 log_out(c, "Bad freeable_cnt %d(main_lebs %d), set lpt incorrect",
     251             :                         c->freeable_cnt, c->main_lebs);
     252           0 :                 goto out_invalid;
     253             :         }
     254    11549750 :         if (c->lst.taken_empty_lebs < 0 ||
     255             :             c->lst.taken_empty_lebs > c->lst.empty_lebs) {
     256           0 :                 log_out(c, "Bad taken_empty_lebs %d(empty_lebs %d), set lpt incorrect",
     257             :                         c->lst.taken_empty_lebs, c->lst.empty_lebs);
     258           0 :                 goto out_invalid;
     259             :         }
     260    11549750 :         if (c->lst.total_free & 7) {
     261           0 :                 log_out(c, "total_free(%lld) is not 8 bytes aligned, set lpt incorrect",
     262             :                         c->lst.total_free);
     263           0 :                 goto out_invalid;
     264             :         }
     265    11549750 :         if (c->lst.total_dirty & 7) {
     266           0 :                 log_out(c, "total_dirty(%lld) is not 8 bytes aligned, set lpt incorrect",
     267             :                         c->lst.total_dirty);
     268           0 :                 goto out_invalid;
     269             :         }
     270    11549750 :         if (c->lst.total_dead & 7) {
     271           0 :                 log_out(c, "total_dead(%lld) is not 8 bytes aligned, set lpt incorrect",
     272             :                         c->lst.total_dead);
     273           0 :                 goto out_invalid;
     274             :         }
     275    11549750 :         if (c->lst.total_dark & 7) {
     276           0 :                 log_out(c, "total_dark(%lld) is not 8 bytes aligned, set lpt incorrect",
     277             :                         c->lst.total_dark);
     278           0 :                 goto out_invalid;
     279             :         }
     280    11549750 :         if (c->lst.total_used & 7) {
     281           0 :                 log_out(c, "total_used(%lld) is not 8 bytes aligned, set lpt incorrect",
     282             :                         c->lst.total_used);
     283           0 :                 goto out_invalid;
     284             :         }
     285    11549750 :         if (old_free != LPROPS_NC && (old_free & 7)) {
     286           0 :                 log_out(c, "LEB %d old_free(%d) is not 8 bytes aligned, set lpt incorrect",
     287             :                         lnum, old_free);
     288           0 :                 goto out_invalid;
     289             :         }
     290    11549750 :         if (old_dirty != LPROPS_NC && (old_dirty & 7)) {
     291           0 :                 log_out(c, "LEB %d old_dirty(%d) is not 8 bytes aligned, set lpt incorrect",
     292             :                         lnum, old_dirty);
     293           0 :                 goto out_invalid;
     294             :         }
     295    11549750 :         if (free != LPROPS_NC && (free < 0 || free > c->leb_size)) {
     296           0 :                 log_out(c, "LEB %d bad free %d(leb_size %d), set lpt incorrect",
     297             :                         lnum, free, c->leb_size);
     298           0 :                 goto out_invalid;
     299             :         }
     300    11549750 :         if (dirty != LPROPS_NC && dirty < 0) {
     301             :                 /* Dirty may be more than c->leb_size before set_bud_lprops. */
     302           0 :                 log_out(c, "LEB %d bad dirty %d(leb_size %d), set lpt incorrect",
     303             :                         lnum, dirty, c->leb_size);
     304           0 :                 goto out_invalid;
     305             :         }
     306             : 
     307    23187228 : out:
     308             :         return true;
     309             : 
     310           0 : out_invalid:
     311           0 :         FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
     312           0 :         return false;
     313             : }
     314             : 
     315          89 : static bool fsck_can_ignore_failure(const struct ubifs_info *c,
     316             :                                     unsigned int reason)
     317             : {
     318          89 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     319             : 
     320          89 :         if (c->cmt_state != COMMIT_RESTING)
     321             :                 /* Don't ignore failure when do commit. */
     322             :                 return false;
     323          89 :         if (reason & (FR_LPT_CORRUPTED | FR_LPT_INCORRECT))
     324             :                 return true;
     325             : 
     326          18 :         return false;
     327             : }
     328             : 
     329             : static const unsigned int reason_mapping_table[] = {
     330             :         BUD_CORRUPTED,          /* FR_H_BUD_CORRUPTED */
     331             :         TNC_DATA_CORRUPTED,     /* FR_H_TNC_DATA_CORRUPTED */
     332             :         ORPHAN_CORRUPTED,       /* FR_H_ORPHAN_CORRUPTED */
     333             :         LTAB_INCORRECT,         /* FR_H_LTAB_INCORRECT */
     334             : };
     335             : 
     336          34 : static bool fsck_handle_failure(const struct ubifs_info *c, unsigned int reason,
     337             :                                 void *priv)
     338             : {
     339          34 :         ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
     340             : 
     341          34 :         return fix_problem(c, reason_mapping_table[reason], priv);
     342             : }
     343             : 
     344           2 : static void signal_cancel(int sig)
     345             : {
     346           2 :         ubifs_warn(c, "killed by signo %d", sig);
     347           2 :         exit_code |= FSCK_CANCELED;
     348           2 :         exit(exit_code);
     349             : }
     350             : 
     351        2519 : static int init_fsck_info(struct ubifs_info *c, int argc, char *argv[])
     352             : {
     353        2519 :         int err = 0, mode = NORMAL_MODE;
     354             :         struct sigaction sa;
     355        2519 :         struct ubifs_fsck_info *fsck = NULL;
     356             : 
     357        2519 :         if (atexit(exit_callback)) {
     358           0 :                 log_err(c, errno, "can not set exit callback");
     359           0 :                 return -errno;
     360             :         }
     361             : 
     362        2519 :         init_ubifs_info(c, FSCK_PROGRAM_TYPE);
     363        2519 :         get_options(argc, argv, &mode);
     364             : 
     365        2494 :         fsck = calloc(1, sizeof(struct ubifs_fsck_info));
     366        2494 :         if (!fsck) {
     367           0 :                 err = -errno;
     368           0 :                 log_err(c, errno, "can not allocate fsck info");
     369           0 :                 goto out_err;
     370             :         }
     371             : 
     372        2494 :         c->private = fsck;
     373        2494 :         FSCK(c)->mode = mode;
     374        4988 :         INIT_LIST_HEAD(&FSCK(c)->disconnected_files);
     375        2494 :         c->assert_failed_cb = fsck_assert_failed;
     376        2494 :         c->set_failure_reason_cb = fsck_set_failure_reason;
     377        2494 :         c->get_failure_reason_cb = fsck_get_failure_reason;
     378        2494 :         c->clear_failure_reason_cb = fsck_clear_failure_reason;
     379        2494 :         c->test_and_clear_failure_reason_cb = fsck_test_and_clear_failure_reason;
     380        2494 :         c->set_lpt_invalid_cb = fsck_set_lpt_invalid;
     381        2494 :         c->test_lpt_valid_cb = fsck_test_lpt_valid;
     382        2494 :         c->can_ignore_failure_cb = fsck_can_ignore_failure;
     383        2494 :         c->handle_failure_cb = fsck_handle_failure;
     384             : 
     385        2494 :         memset(&sa, 0, sizeof(struct sigaction));
     386        2494 :         sa.sa_handler = signal_cancel;
     387        2494 :         if (sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)) {
     388           0 :                 err = -errno;
     389           0 :                 log_err(c, errno, "can not set signal handler");
     390           0 :                 goto out_err;
     391             :         }
     392             : 
     393             :         return 0;
     394             : 
     395           0 : out_err:
     396           0 :         free(fsck);
     397           0 :         free(c->dev_name);
     398           0 :         c->dev_name = NULL;
     399           0 :         return err;
     400             : }
     401             : 
     402             : static void destroy_fsck_info(struct ubifs_info *c)
     403             : {
     404        2122 :         free(c->private);
     405        2122 :         c->private = NULL;
     406        2122 :         free(c->dev_name);
     407        2122 :         c->dev_name = NULL;
     408             : }
     409             : 
     410         523 : void handle_error(const struct ubifs_info *c, int reason_set)
     411             : {
     412         523 :         bool handled = false;
     413         523 :         unsigned int reason = get_failure_reason_callback(c);
     414             : 
     415         523 :         clear_failure_reason_callback(c);
     416         523 :         if ((reason_set & HAS_DATA_CORRUPTED) && (reason & FR_DATA_CORRUPTED)) {
     417          21 :                 handled = true;
     418          21 :                 reason &= ~FR_DATA_CORRUPTED;
     419          21 :                 if (fix_problem(c, LOG_CORRUPTED, NULL))
     420           5 :                         FSCK(c)->try_rebuild = true;
     421             :         }
     422         507 :         if ((reason_set & HAS_TNC_CORRUPTED) && (reason & FR_TNC_CORRUPTED)) {
     423         498 :                 ubifs_assert(c, !handled);
     424         498 :                 handled = true;
     425         498 :                 reason &= ~FR_TNC_CORRUPTED;
     426         498 :                 if (fix_problem(c, TNC_CORRUPTED, NULL))
     427         410 :                         FSCK(c)->try_rebuild = true;
     428             :         }
     429             : 
     430         419 :         ubifs_assert(c, reason == 0);
     431         419 :         if (!handled)
     432           4 :                 exit_code |= FSCK_ERROR;
     433         419 : }
     434             : 
     435        2996 : static int commit_fix_modifications(struct ubifs_info *c, bool final_commit)
     436             : {
     437             :         int err;
     438             : 
     439        2996 :         if (final_commit) {
     440        1497 :                 log_out(c, "Final committing");
     441        1497 :                 c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
     442        1497 :                 c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum);
     443             :                 /* Force UBIFS to do commit by setting @c->mounting. */
     444        1497 :                 c->mounting = 1;
     445        1499 :         } else if (exit_code & FSCK_NONDESTRUCT) {
     446         167 :                 log_out(c, "Commit problem fixing modifications");
     447             :                 /* Force UBIFS to do commit by setting @c->mounting. */
     448         167 :                 c->mounting = 1;
     449             :         }
     450             : 
     451        2996 :         err = ubifs_run_commit(c);
     452             : 
     453        2996 :         if (c->mounting)
     454        1664 :                 c->mounting = 0;
     455             : 
     456        2996 :         return err;
     457             : }
     458             : 
     459             : /*
     460             :  * do_fsck - Check & repair the filesystem.
     461             :  */
     462        2196 : static int do_fsck(void)
     463             : {
     464             :         int err;
     465             : 
     466        4392 :         log_out(c, "Traverse TNC and construct files");
     467        2196 :         err = traverse_tnc_and_construct_files(c);
     468        2052 :         if (err) {
     469         474 :                 handle_error(c, HAS_TNC_CORRUPTED);
     470         408 :                 return err;
     471             :         }
     472             : 
     473        1578 :         update_files_size(c);
     474             : 
     475        3156 :         log_out(c, "Check and handle invalid files");
     476        1578 :         err = handle_invalid_files(c);
     477        1555 :         if (err) {
     478           0 :                 exit_code |= FSCK_ERROR;
     479           0 :                 goto free_used_lebs;
     480             :         }
     481             : 
     482        3110 :         log_out(c, "Check and handle unreachable files");
     483        1555 :         err = handle_dentry_tree(c);
     484        1555 :         if (err) {
     485           0 :                 exit_code |= FSCK_ERROR;
     486           0 :                 goto free_disconnected_files;
     487             :         }
     488             : 
     489        3110 :         log_out(c, "Check and correct files");
     490        1555 :         err = check_and_correct_files(c);
     491        1555 :         if (err) {
     492           2 :                 exit_code |= FSCK_ERROR;
     493           2 :                 goto free_disconnected_files;
     494             :         }
     495             : 
     496        3106 :         log_out(c, "Check whether the TNC is empty");
     497        1553 :         if (tnc_is_empty(c) && fix_problem(c, EMPTY_TNC, NULL)) {
     498           3 :                 err = -EINVAL;
     499           3 :                 FSCK(c)->try_rebuild = true;
     500           3 :                 goto free_disconnected_files;
     501             :         }
     502             : 
     503        1547 :         err = check_and_correct_space(c);
     504        3054 :         kfree(FSCK(c)->used_lebs);
     505        1527 :         destroy_file_tree(c, &FSCK(c)->scanned_files);
     506        1527 :         if (err) {
     507          28 :                 exit_code |= FSCK_ERROR;
     508          28 :                 goto free_disconnected_files_2;
     509             :         }
     510             : 
     511             :         /*
     512             :          * Committing is required once before allocating new space(subsequent
     513             :          * steps may need), because building lpt could mark LEB(which holds
     514             :          * stale data nodes) as unused, if the LEB is overwritten by new data,
     515             :          * old data won't be found in the next fsck run(assume that first fsck
     516             :          * run is interrupted by the powercut), which could affect the
     517             :          * correctness of LEB properties after replaying journal in the second
     518             :          * fsck run.
     519             :          */
     520        1499 :         err = commit_fix_modifications(c, false);
     521        1499 :         if (err) {
     522           2 :                 exit_code |= FSCK_ERROR;
     523           2 :                 goto free_disconnected_files_2;
     524             :         }
     525             : 
     526        2994 :         log_out(c, "Check and correct the index size");
     527        1497 :         err = check_and_correct_index_size(c);
     528        1497 :         if (err) {
     529           0 :                 exit_code |= FSCK_ERROR;
     530           0 :                 goto free_disconnected_files_2;
     531             :         }
     532             : 
     533        2994 :         log_out(c, "Check and create root dir");
     534        1497 :         err = check_and_create_root(c);
     535        1497 :         if (err) {
     536           0 :                 exit_code |= FSCK_ERROR;
     537           0 :                 goto free_disconnected_files_2;
     538             :         }
     539             : 
     540        2994 :         if (list_empty(&FSCK(c)->disconnected_files))
     541             :                 goto final_commit;
     542             : 
     543          74 :         log_out(c, "Check and create lost+found");
     544          37 :         err = check_and_create_lost_found(c);
     545          37 :         if (err) {
     546           0 :                 exit_code |= FSCK_ERROR;
     547           0 :                 goto free_disconnected_files_2;
     548             :         }
     549             : 
     550          74 :         log_out(c, "Handle disconnected files");
     551          37 :         err = handle_disonnected_files(c);
     552          37 :         if (err) {
     553           0 :                 exit_code |= FSCK_ERROR;
     554           0 :                 goto free_disconnected_files_2;
     555             :         }
     556             : 
     557        1497 : final_commit:
     558        1497 :         err = commit_fix_modifications(c, true);
     559        1497 :         if (err)
     560           0 :                 exit_code |= FSCK_ERROR;
     561             : 
     562             :         return err;
     563             : 
     564          30 : free_disconnected_files_2:
     565          30 :         destroy_file_list(c, &FSCK(c)->disconnected_files);
     566          30 :         return err;
     567             : 
     568           5 : free_disconnected_files:
     569           5 :         destroy_file_list(c, &FSCK(c)->disconnected_files);
     570           5 : free_used_lebs:
     571          10 :         kfree(FSCK(c)->used_lebs);
     572           5 :         destroy_file_tree(c, &FSCK(c)->scanned_files);
     573           5 :         return err;
     574             : }
     575             : 
     576        2519 : int main(int argc, char *argv[])
     577             : {
     578             :         int err;
     579             : 
     580        2519 :         err = init_fsck_info(c, argc, argv);
     581        2494 :         if (err) {
     582           0 :                 exit_code |= FSCK_ERROR;
     583           0 :                 goto out_exit;
     584             :         }
     585             : 
     586        2494 :         err = ubifs_open_volume(c, c->dev_name);
     587        2494 :         if (err) {
     588         154 :                 exit_code |= FSCK_ERROR;
     589         154 :                 goto out_destroy_fsck;
     590             :         }
     591             : 
     592             :         /*
     593             :          * Init: Read superblock
     594             :          * Step 1: Read master & init lpt
     595             :          * Step 2: Replay journal
     596             :          * Step 3: Handle orphan nodes
     597             :          * Step 4: Consolidate log
     598             :          * Step 5: Recover isize
     599             :          */
     600        2340 :         err = ubifs_load_filesystem(c);
     601        2224 :         if (err) {
     602          28 :                 if (FSCK(c)->try_rebuild)
     603          18 :                         ubifs_rebuild_filesystem(c);
     604             :                 goto out_close;
     605             :         }
     606             : 
     607             :         /*
     608             :          * Step 6: Traverse tnc and construct files
     609             :          * Step 7: Update files' size
     610             :          * Step 8: Check and handle invalid files
     611             :          * Step 9: Check and handle unreachable files
     612             :          * Step 10: Check and correct files
     613             :          * Step 11: Check whether the TNC is empty
     614             :          * Step 12: Check and correct the space statistics
     615             :          * Step 13: Commit problem fixing modifications
     616             :          * Step 14: Check and correct the index size
     617             :          * Step 15: Check and create root dir
     618             :          * Step 16: Check and create lost+found
     619             :          * Step 17: Handle disconnected files
     620             :          * Step 18: Do final committing
     621             :          */
     622        2196 :         err = do_fsck();
     623        1940 :         if (err && FSCK(c)->try_rebuild) {
     624         407 :                 ubifs_destroy_filesystem(c);
     625         407 :                 ubifs_rebuild_filesystem(c);
     626             :         } else {
     627        1533 :                 ubifs_destroy_filesystem(c);
     628             :         }
     629             : 
     630        1968 : out_close:
     631        1968 :         ubifs_close_volume(c);
     632        2122 : out_destroy_fsck:
     633        2122 :         destroy_fsck_info(c);
     634        2122 : out_exit:
     635        2122 :         return exit_code;
     636             : }

Generated by: LCOV version 1.13