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 : }
|