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 "bitops.h"
12 : #include "kmem.h"
13 : #include "ubifs.h"
14 : #include "defs.h"
15 : #include "debug.h"
16 : #include "key.h"
17 : #include "misc.h"
18 : #include "fsck.ubifs.h"
19 :
20 2340 : int ubifs_load_filesystem(struct ubifs_info *c)
21 : {
22 : int err;
23 : size_t sz;
24 :
25 2340 : err = init_constants_early(c);
26 2340 : if (err) {
27 8 : exit_code |= FSCK_ERROR;
28 8 : return err;
29 : }
30 :
31 2332 : err = check_volume_empty(c);
32 2332 : if (err <= 0) {
33 0 : exit_code |= FSCK_ERROR;
34 0 : log_err(c, 0, "%s UBI volume!", err < 0 ? "bad" : "empty");
35 0 : return -EINVAL;
36 : }
37 :
38 2332 : if (c->ro_media && !c->ro_mount) {
39 0 : exit_code |= FSCK_ERROR;
40 0 : log_err(c, 0, "cannot read-write on read-only media");
41 0 : return -EROFS;
42 : }
43 :
44 2332 : err = -ENOMEM;
45 2332 : c->bottom_up_buf = kmalloc_array(BOTTOM_UP_HEIGHT, sizeof(int),
46 : GFP_KERNEL);
47 2332 : if (!c->bottom_up_buf) {
48 0 : exit_code |= FSCK_ERROR;
49 0 : log_err(c, errno, "cannot allocate bottom_up_buf");
50 0 : goto out_free;
51 : }
52 :
53 2332 : c->sbuf = vmalloc(c->leb_size);
54 2332 : if (!c->sbuf) {
55 0 : exit_code |= FSCK_ERROR;
56 0 : log_err(c, errno, "cannot allocate sbuf");
57 0 : goto out_free;
58 : }
59 :
60 2332 : if (!c->ro_mount) {
61 2200 : c->ileb_buf = vmalloc(c->leb_size);
62 2200 : if (!c->ileb_buf) {
63 0 : exit_code |= FSCK_ERROR;
64 0 : log_err(c, errno, "cannot allocate ileb_buf");
65 0 : goto out_free;
66 : }
67 : }
68 :
69 2332 : c->mounting = 1;
70 :
71 2332 : log_out(c, "Read superblock");
72 2332 : err = ubifs_read_superblock(c);
73 2332 : if (err) {
74 48 : if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED))
75 48 : fix_problem(c, SB_CORRUPTED, NULL);
76 0 : exit_code |= FSCK_ERROR;
77 0 : goto out_mounting;
78 : }
79 :
80 2284 : err = init_constants_sb(c);
81 2284 : if (err) {
82 0 : exit_code |= FSCK_ERROR;
83 0 : goto out_mounting;
84 : }
85 :
86 2284 : sz = ALIGN(c->max_idx_node_sz, c->min_io_size) * 2;
87 2284 : c->cbuf = kmalloc(sz, GFP_NOFS);
88 2284 : if (!c->cbuf) {
89 0 : err = -ENOMEM;
90 0 : exit_code |= FSCK_ERROR;
91 0 : log_err(c, errno, "cannot allocate cbuf");
92 0 : goto out_mounting;
93 : }
94 :
95 2284 : err = alloc_wbufs(c);
96 2284 : if (err) {
97 0 : exit_code |= FSCK_ERROR;
98 0 : log_err(c, 0, "cannot allocate wbuf");
99 0 : goto out_mounting;
100 : }
101 :
102 2284 : log_out(c, "Read master & init lpt");
103 2284 : err = ubifs_read_master(c);
104 2284 : if (err) {
105 19 : if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED)) {
106 19 : if (fix_problem(c, MST_CORRUPTED, NULL))
107 7 : FSCK(c)->try_rebuild = true;
108 : } else
109 0 : exit_code |= FSCK_ERROR;
110 : goto out_master;
111 : }
112 :
113 2265 : init_constants_master(c);
114 :
115 2265 : if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
116 1155 : ubifs_msg(c, "recovery needed");
117 1155 : c->need_recovery = 1;
118 : }
119 :
120 2265 : if (c->need_recovery && !c->ro_mount) {
121 1033 : err = ubifs_recover_inl_heads(c, c->sbuf);
122 1033 : if (err) {
123 0 : exit_code |= FSCK_ERROR;
124 0 : goto out_master;
125 : }
126 : }
127 :
128 2265 : err = ubifs_lpt_init(c, 1, !c->ro_mount);
129 2265 : if (err) {
130 0 : exit_code |= FSCK_ERROR;
131 0 : goto out_master;
132 : }
133 :
134 2265 : if (!c->ro_mount && c->space_fixup) {
135 128 : err = ubifs_fixup_free_space(c);
136 128 : if (err) {
137 0 : exit_code |= FSCK_ERROR;
138 0 : goto out_lpt;
139 : }
140 : }
141 :
142 2265 : if (!c->ro_mount && !c->need_recovery) {
143 : /*
144 : * Set the "dirty" flag so that if we reboot uncleanly we
145 : * will notice this immediately on the next mount.
146 : */
147 1100 : c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
148 1100 : err = ubifs_write_master(c);
149 1100 : if (err) {
150 2 : exit_code |= FSCK_ERROR;
151 2 : goto out_lpt;
152 : }
153 : }
154 :
155 2263 : if (!c->ro_mount && c->superblock_need_write) {
156 260 : err = ubifs_write_sb_node(c, c->sup_node);
157 260 : if (err) {
158 0 : exit_code |= FSCK_ERROR;
159 0 : goto out_lpt;
160 : }
161 260 : c->superblock_need_write = 0;
162 : }
163 :
164 2263 : log_out(c, "Replay journal");
165 2263 : err = ubifs_replay_journal(c);
166 2248 : if (err) {
167 49 : handle_error(c, HAS_DATA_CORRUPTED | HAS_TNC_CORRUPTED);
168 11 : goto out_journal;
169 : }
170 :
171 : /* Calculate 'min_idx_lebs' after journal replay */
172 2199 : c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
173 :
174 2199 : log_out(c, "Handle orphan nodes");
175 2199 : err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
176 2196 : if (err) {
177 0 : handle_error(c, HAS_TNC_CORRUPTED);
178 0 : goto out_orphans;
179 : }
180 :
181 2196 : if (!c->ro_mount) {
182 : int lnum;
183 :
184 : /* Check for enough log space */
185 2092 : lnum = c->lhead_lnum + 1;
186 2092 : if (lnum >= UBIFS_LOG_LNUM + c->log_lebs)
187 387 : lnum = UBIFS_LOG_LNUM;
188 2092 : if (lnum == c->ltail_lnum) {
189 17 : log_out(c, "Consolidate log");
190 17 : err = ubifs_consolidate_log(c);
191 17 : if (err) {
192 0 : handle_error(c, HAS_DATA_CORRUPTED);
193 0 : goto out_orphans;
194 : }
195 : }
196 :
197 2092 : if (c->need_recovery) {
198 994 : log_out(c, "Recover isize");
199 994 : err = ubifs_recover_size(c, true);
200 994 : if (err) {
201 0 : handle_error(c, HAS_TNC_CORRUPTED);
202 0 : goto out_orphans;
203 : }
204 : }
205 104 : } else if (c->need_recovery) {
206 94 : log_out(c, "Recover isize");
207 94 : err = ubifs_recover_size(c, false);
208 94 : if (err) {
209 0 : handle_error(c, HAS_TNC_CORRUPTED);
210 0 : goto out_orphans;
211 : }
212 : }
213 :
214 2196 : c->mounting = 0;
215 :
216 2196 : return 0;
217 :
218 0 : out_orphans:
219 0 : free_orphans(c);
220 11 : out_journal:
221 11 : destroy_journal(c);
222 13 : out_lpt:
223 13 : ubifs_lpt_free(c, 0);
224 20 : out_master:
225 20 : c->max_sqnum = 0;
226 20 : c->highest_inum = 0;
227 20 : c->calc_idx_sz = 0;
228 40 : kfree(c->mst_node);
229 40 : kfree(c->rcvrd_mst_node);
230 20 : free_wbufs(c);
231 20 : out_mounting:
232 20 : c->mounting = 0;
233 20 : out_free:
234 40 : kfree(c->cbuf);
235 40 : kfree(c->ileb_buf);
236 40 : kfree(c->sbuf);
237 40 : kfree(c->bottom_up_buf);
238 40 : kfree(c->sup_node);
239 :
240 20 : return err;
241 : }
242 :
243 1940 : void ubifs_destroy_filesystem(struct ubifs_info *c)
244 : {
245 1940 : destroy_journal(c);
246 1940 : free_wbufs(c);
247 1940 : free_orphans(c);
248 1940 : ubifs_lpt_free(c, 0);
249 :
250 1940 : c->max_sqnum = 0;
251 1940 : c->highest_inum = 0;
252 1940 : c->calc_idx_sz = 0;
253 :
254 3880 : kfree(c->cbuf);
255 3880 : kfree(c->rcvrd_mst_node);
256 3880 : kfree(c->mst_node);
257 3880 : kfree(c->ileb_buf);
258 3880 : kfree(c->sbuf);
259 3880 : kfree(c->bottom_up_buf);
260 3880 : kfree(c->sup_node);
261 1940 : }
|