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