]>
Commit | Line | Data |
---|---|---|
1b6bf175 TT |
1 | /* |
2 | * e2fsck.c - superblock checks | |
3 | * | |
4 | * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. | |
5 | * | |
6 | * %Begin-Header% | |
7 | * This file may be redistributed under the terms of the GNU Public | |
8 | * License. | |
9 | * %End-Header% | |
10 | */ | |
11 | ||
1b6bf175 TT |
12 | #ifdef HAVE_ERRNO_H |
13 | #include <errno.h> | |
14 | #endif | |
1b6bf175 | 15 | |
54be2ccc | 16 | #ifndef EXT2_SKIP_UUID |
1b6bf175 | 17 | #include "uuid/uuid.h" |
54be2ccc | 18 | #endif |
1b6bf175 TT |
19 | #include "e2fsck.h" |
20 | #include "problem.h" | |
1b6bf175 TT |
21 | |
22 | #define MIN_CHECK 1 | |
23 | #define MAX_CHECK 2 | |
24 | ||
25 | static void check_super_value(e2fsck_t ctx, const char *descr, | |
26 | unsigned long value, int flags, | |
7f813ba3 | 27 | unsigned long min_val, unsigned long max_val) |
1b6bf175 TT |
28 | { |
29 | struct problem_context pctx; | |
30 | ||
7f813ba3 TT |
31 | if (((flags & MIN_CHECK) && (value < min_val)) || |
32 | ((flags & MAX_CHECK) && (value > max_val))) { | |
1b6bf175 TT |
33 | clear_problem_context(&pctx); |
34 | pctx.num = value; | |
35 | pctx.str = descr; | |
36 | fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); | |
08b21301 | 37 | ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ |
1b6bf175 TT |
38 | } |
39 | } | |
40 | ||
4313932c TT |
41 | /* |
42 | * This routine may get stubbed out in special compilations of the | |
43 | * e2fsck code.. | |
44 | */ | |
45 | #ifndef EXT2_SPECIAL_DEVICE_SIZE | |
46 | errcode_t e2fsck_get_device_size(e2fsck_t ctx) | |
47 | { | |
48 | return (ext2fs_get_device_size(ctx->filesystem_name, | |
49 | EXT2_BLOCK_SIZE(ctx->fs->super), | |
50 | &ctx->num_blocks)); | |
51 | } | |
4313932c TT |
52 | #endif |
53 | ||
80bfaa3e TT |
54 | /* |
55 | * helper function to release an inode | |
56 | */ | |
57 | struct process_block_struct { | |
8394902e TT |
58 | e2fsck_t ctx; |
59 | char *buf; | |
80bfaa3e | 60 | struct problem_context *pctx; |
8394902e TT |
61 | int truncating; |
62 | int truncate_offset; | |
63 | blk_t truncate_block; | |
64 | int truncated_blocks; | |
65 | int abort; | |
66 | errcode_t errcode; | |
80bfaa3e TT |
67 | }; |
68 | ||
69 | static int release_inode_block(ext2_filsys fs, | |
70 | blk_t *block_nr, | |
71 | int blockcnt, | |
72 | void *priv_data) | |
73 | { | |
74 | struct process_block_struct *pb; | |
8394902e TT |
75 | e2fsck_t ctx; |
76 | struct problem_context *pctx; | |
77 | blk_t blk = *block_nr; | |
78 | int retval = 0; | |
80bfaa3e TT |
79 | |
80 | pb = (struct process_block_struct *) priv_data; | |
81 | ctx = pb->ctx; | |
82 | pctx = pb->pctx; | |
83 | ||
84 | pctx->blk = blk; | |
85 | pctx->blkcount = blockcnt; | |
86 | ||
87 | if (HOLE_BLKADDR(blk)) | |
88 | return 0; | |
89 | ||
90 | if ((blk < fs->super->s_first_data_block) || | |
91 | (blk >= fs->super->s_blocks_count)) { | |
92 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx); | |
8394902e | 93 | abort: |
80bfaa3e TT |
94 | pb->abort = 1; |
95 | return BLOCK_ABORT; | |
96 | } | |
97 | ||
98 | if (!ext2fs_test_block_bitmap(fs->block_map, blk)) { | |
99 | fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx); | |
8394902e TT |
100 | goto abort; |
101 | } | |
102 | ||
103 | /* | |
104 | * If we are deleting an orphan, then we leave the fields alone. | |
105 | * If we are truncating an orphan, then update the inode fields | |
106 | * and clean up any partial block data. | |
107 | */ | |
108 | if (pb->truncating) { | |
109 | /* | |
110 | * We only remove indirect blocks if they are | |
111 | * completely empty. | |
112 | */ | |
113 | if (blockcnt < 0) { | |
114 | int i, limit; | |
115 | blk_t *block_nr; | |
116 | ||
117 | pb->errcode = io_channel_read_blk(fs->io, blk, 1, | |
118 | pb->buf); | |
119 | if (pb->errcode) | |
120 | goto abort; | |
121 | ||
122 | limit = fs->blocksize >> 2; | |
123 | for (i = 0, block_nr = (blk_t *) pb->buf; | |
124 | i < limit; i++, block_nr++) | |
125 | if (*block_nr) | |
126 | return 0; | |
127 | } | |
128 | /* | |
129 | * We don't remove direct blocks until we've reached | |
130 | * the truncation block. | |
131 | */ | |
132 | if (blockcnt >= 0 && blockcnt < pb->truncate_block) | |
133 | return 0; | |
134 | /* | |
135 | * If part of the last block needs truncating, we do | |
136 | * it here. | |
137 | */ | |
138 | if ((blockcnt == pb->truncate_block) && pb->truncate_offset) { | |
139 | pb->errcode = io_channel_read_blk(fs->io, blk, 1, | |
140 | pb->buf); | |
141 | if (pb->errcode) | |
142 | goto abort; | |
143 | memset(pb->buf + pb->truncate_offset, 0, | |
144 | fs->blocksize - pb->truncate_offset); | |
145 | pb->errcode = io_channel_write_blk(fs->io, blk, 1, | |
146 | pb->buf); | |
147 | if (pb->errcode) | |
148 | goto abort; | |
149 | } | |
150 | pb->truncated_blocks++; | |
151 | *block_nr = 0; | |
152 | retval |= BLOCK_CHANGED; | |
80bfaa3e TT |
153 | } |
154 | ||
155 | ext2fs_unmark_block_bitmap(fs->block_map, blk); | |
ecf1b776 TT |
156 | fs->group_desc[ext2fs_group_of_blk(fs, blk)].bg_free_blocks_count++; |
157 | fs->super->s_free_blocks_count++; | |
80bfaa3e | 158 | |
8394902e | 159 | return retval; |
80bfaa3e TT |
160 | } |
161 | ||
162 | /* | |
163 | * This function releases an inode. Returns 1 if an inconsistency was | |
8394902e TT |
164 | * found. If the inode has a link count, then it is being truncated and |
165 | * not deleted. | |
80bfaa3e | 166 | */ |
8394902e TT |
167 | static int release_inode_blocks(e2fsck_t ctx, ino_t ino, |
168 | struct ext2_inode *inode, char* block_buf, | |
80bfaa3e TT |
169 | struct problem_context *pctx) |
170 | { | |
8394902e | 171 | ext2_filsys fs = ctx->fs; |
80bfaa3e TT |
172 | errcode_t retval; |
173 | struct process_block_struct pb; | |
174 | ||
8394902e | 175 | pb.buf = block_buf + 3 * ctx->fs->blocksize; |
80bfaa3e TT |
176 | pb.ctx = ctx; |
177 | pb.abort = 0; | |
8394902e | 178 | pb.errcode = 0; |
80bfaa3e | 179 | pb.pctx = pctx; |
8394902e TT |
180 | if (inode->i_links_count) { |
181 | pb.truncating = 1; | |
182 | pb.truncate_block = (blk_t) | |
183 | ((((long long)inode->i_size_high << 32) + | |
184 | inode->i_size + fs->blocksize - 1) / | |
185 | fs->blocksize); | |
186 | pb.truncate_offset = inode->i_size % fs->blocksize; | |
187 | } else { | |
188 | pb.truncating = 0; | |
189 | pb.truncate_block = 0; | |
190 | pb.truncate_offset = 0; | |
191 | } | |
192 | pb.truncated_blocks = 0; | |
193 | retval = ext2fs_block_iterate(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE, | |
194 | block_buf, release_inode_block, &pb); | |
80bfaa3e | 195 | if (retval) { |
8394902e | 196 | com_err("release_inode_blocks", retval, |
80bfaa3e TT |
197 | _("while calling ext2fs_block_iterate for inode %d"), |
198 | ino); | |
199 | return 1; | |
200 | } | |
201 | if (pb.abort) | |
202 | return 1; | |
203 | ||
8394902e TT |
204 | /* Refresh the inode since ext2fs_block_iterate may have changed it */ |
205 | e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks"); | |
206 | ||
207 | if (pb.truncated_blocks) | |
208 | inode->i_blocks -= pb.truncated_blocks * | |
209 | (fs->blocksize / 512); | |
210 | ||
80bfaa3e TT |
211 | ext2fs_mark_bb_dirty(fs); |
212 | return 0; | |
213 | } | |
214 | ||
215 | /* | |
216 | * This function releases all of the orphan inodes. It returns 1 if | |
217 | * it hit some error, and 0 on success. | |
218 | */ | |
219 | static int release_orphan_inodes(e2fsck_t ctx) | |
220 | { | |
221 | ext2_filsys fs = ctx->fs; | |
ecf1b776 | 222 | int group; |
80bfaa3e TT |
223 | ino_t ino, next_ino; |
224 | struct ext2_inode inode; | |
225 | struct problem_context pctx; | |
226 | char *block_buf; | |
227 | ||
228 | if ((ino = fs->super->s_last_orphan) == 0) | |
229 | return 0; | |
230 | ||
25c63ba0 TT |
231 | /* |
232 | * Win or lose, we won't be using the head of the orphan inode | |
233 | * list again. | |
234 | */ | |
235 | fs->super->s_last_orphan = 0; | |
236 | ext2fs_mark_super_dirty(fs); | |
237 | ||
80bfaa3e TT |
238 | if ((ino < EXT2_FIRST_INODE(fs->super)) || |
239 | (ino > fs->super->s_inodes_count)) { | |
240 | clear_problem_context(&pctx); | |
241 | pctx.ino; | |
242 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx); | |
243 | return 1; | |
244 | } | |
245 | ||
8394902e | 246 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, |
9b565759 | 247 | "block iterate buffer"); |
80bfaa3e TT |
248 | e2fsck_read_bitmaps(ctx); |
249 | ||
250 | while (ino) { | |
8394902e | 251 | e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes"); |
80bfaa3e | 252 | clear_problem_context(&pctx); |
ecf1b776 | 253 | pctx.ino = ino; |
80bfaa3e | 254 | pctx.inode = &inode; |
8394902e | 255 | pctx.str = inode.i_links_count ? "Truncating" : "Clearing"; |
80bfaa3e | 256 | |
8394902e | 257 | fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx); |
ecf1b776 | 258 | |
80bfaa3e TT |
259 | next_ino = inode.i_dtime; |
260 | if (next_ino && | |
99a2cc96 TT |
261 | ((next_ino < EXT2_FIRST_INODE(fs->super)) || |
262 | (next_ino > fs->super->s_inodes_count))) { | |
263 | pctx.ino = next_ino; | |
80bfaa3e TT |
264 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx); |
265 | goto abort; | |
266 | } | |
267 | ||
8394902e | 268 | if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx)) |
80bfaa3e | 269 | goto abort; |
ecf1b776 | 270 | |
8394902e TT |
271 | if (!inode.i_links_count) { |
272 | ext2fs_unmark_inode_bitmap(fs->inode_map, ino); | |
273 | ext2fs_mark_ib_dirty(fs); | |
274 | group = ext2fs_group_of_ino(fs, ino); | |
275 | fs->group_desc[group].bg_free_inodes_count++; | |
276 | fs->super->s_free_inodes_count++; | |
277 | if (LINUX_S_ISDIR(inode.i_mode)) | |
278 | fs->group_desc[group].bg_used_dirs_count--; | |
279 | ||
280 | inode.i_dtime = time(0); | |
281 | } | |
282 | e2fsck_write_inode(ctx, ino, &inode, "delete_file"); | |
80bfaa3e TT |
283 | ino = next_ino; |
284 | } | |
285 | return 0; | |
286 | abort: | |
287 | ext2fs_free_mem((void **) &block_buf); | |
288 | return 1; | |
289 | } | |
290 | ||
291 | ||
1b6bf175 TT |
292 | void check_super_block(e2fsck_t ctx) |
293 | { | |
294 | ext2_filsys fs = ctx->fs; | |
295 | blk_t first_block, last_block; | |
5dd8f963 | 296 | struct ext2_super_block *sb = fs->super; |
1b6bf175 | 297 | blk_t blocks_per_group = fs->super->s_blocks_per_group; |
78cf0547 | 298 | int inodes_per_block; |
7f813ba3 | 299 | dgrp_t i; |
1b6bf175 TT |
300 | blk_t should_be; |
301 | struct problem_context pctx; | |
78cf0547 TT |
302 | |
303 | inodes_per_block = (EXT2_INODE_SIZE(fs->super) + | |
304 | EXT2_BLOCK_SIZE(fs->super) - 1) / | |
305 | EXT2_BLOCK_SIZE(fs->super); | |
1b6bf175 | 306 | |
54dc7ca2 | 307 | ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, |
f8188fff | 308 | sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap"); |
54dc7ca2 | 309 | ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, |
f8188fff | 310 | sizeof(int) * fs->group_desc_count, "invalid_block_bitmap"); |
54dc7ca2 | 311 | ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx, |
f8188fff | 312 | sizeof(int) * fs->group_desc_count, "invalid_inode_table"); |
1b6bf175 TT |
313 | |
314 | clear_problem_context(&pctx); | |
315 | ||
316 | /* | |
317 | * Verify the super block constants... | |
318 | */ | |
5dd8f963 | 319 | check_super_value(ctx, "inodes_count", sb->s_inodes_count, |
1b6bf175 | 320 | MIN_CHECK, 1, 0); |
5dd8f963 | 321 | check_super_value(ctx, "blocks_count", sb->s_blocks_count, |
1b6bf175 | 322 | MIN_CHECK, 1, 0); |
5dd8f963 TT |
323 | check_super_value(ctx, "first_data_block", sb->s_first_data_block, |
324 | MAX_CHECK, 0, sb->s_blocks_count); | |
325 | check_super_value(ctx, "log_frag_size", sb->s_log_frag_size, | |
1b6bf175 | 326 | MAX_CHECK, 0, 2); |
5dd8f963 TT |
327 | check_super_value(ctx, "log_block_size", sb->s_log_block_size, |
328 | MIN_CHECK | MAX_CHECK, sb->s_log_frag_size, | |
1b6bf175 | 329 | 2); |
5dd8f963 TT |
330 | check_super_value(ctx, "frags_per_group", sb->s_frags_per_group, |
331 | MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(sb)); | |
332 | check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group, | |
333 | MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(sb)); | |
334 | check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group, | |
78cf0547 TT |
335 | MIN_CHECK | MAX_CHECK, 1, |
336 | inodes_per_block * blocks_per_group); | |
5dd8f963 TT |
337 | check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count, |
338 | MAX_CHECK, 0, sb->s_blocks_count); | |
1b6bf175 | 339 | |
f8188fff | 340 | if (!ctx->num_blocks) { |
4313932c | 341 | pctx.errcode = e2fsck_get_device_size(ctx); |
f8188fff TT |
342 | if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) { |
343 | fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx); | |
08b21301 TT |
344 | ctx->flags |= E2F_FLAG_ABORT; |
345 | return; | |
346 | } | |
f8188fff | 347 | if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) && |
5dd8f963 TT |
348 | (ctx->num_blocks < sb->s_blocks_count)) { |
349 | pctx.blk = sb->s_blocks_count; | |
f8188fff TT |
350 | pctx.blk2 = ctx->num_blocks; |
351 | if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) { | |
352 | ctx->flags |= E2F_FLAG_ABORT; | |
353 | return; | |
354 | } | |
355 | } | |
1b6bf175 TT |
356 | } |
357 | ||
5dd8f963 TT |
358 | if (sb->s_log_block_size != sb->s_log_frag_size) { |
359 | pctx.blk = EXT2_BLOCK_SIZE(sb); | |
360 | pctx.blk2 = EXT2_FRAG_SIZE(sb); | |
1b6bf175 | 361 | fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx); |
08b21301 TT |
362 | ctx->flags |= E2F_FLAG_ABORT; |
363 | return; | |
1b6bf175 TT |
364 | } |
365 | ||
5dd8f963 TT |
366 | should_be = sb->s_frags_per_group >> |
367 | (sb->s_log_block_size - sb->s_log_frag_size); | |
368 | if (sb->s_blocks_per_group != should_be) { | |
369 | pctx.blk = sb->s_blocks_per_group; | |
1b6bf175 TT |
370 | pctx.blk2 = should_be; |
371 | fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx); | |
08b21301 TT |
372 | ctx->flags |= E2F_FLAG_ABORT; |
373 | return; | |
1b6bf175 TT |
374 | } |
375 | ||
5dd8f963 TT |
376 | should_be = (sb->s_log_block_size == 0) ? 1 : 0; |
377 | if (sb->s_first_data_block != should_be) { | |
378 | pctx.blk = sb->s_first_data_block; | |
1b6bf175 TT |
379 | pctx.blk2 = should_be; |
380 | fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx); | |
08b21301 TT |
381 | ctx->flags |= E2F_FLAG_ABORT; |
382 | return; | |
1b6bf175 TT |
383 | } |
384 | ||
5dd8f963 TT |
385 | should_be = sb->s_inodes_per_group * fs->group_desc_count; |
386 | if (sb->s_inodes_count != should_be) { | |
387 | pctx.ino = sb->s_inodes_count; | |
d4b0ce03 TT |
388 | pctx.ino2 = should_be; |
389 | if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) { | |
5dd8f963 | 390 | sb->s_inodes_count = should_be; |
d4b0ce03 TT |
391 | ext2fs_mark_super_dirty(fs); |
392 | } | |
393 | } | |
394 | ||
1b6bf175 TT |
395 | /* |
396 | * Verify the group descriptors.... | |
397 | */ | |
398 | first_block = fs->super->s_first_data_block; | |
399 | last_block = first_block + blocks_per_group; | |
400 | ||
401 | for (i = 0; i < fs->group_desc_count; i++) { | |
402 | pctx.group = i; | |
403 | ||
404 | if (i == fs->group_desc_count - 1) | |
405 | last_block = fs->super->s_blocks_count; | |
406 | if ((fs->group_desc[i].bg_block_bitmap < first_block) || | |
407 | (fs->group_desc[i].bg_block_bitmap >= last_block)) { | |
408 | pctx.blk = fs->group_desc[i].bg_block_bitmap; | |
409 | if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) { | |
410 | fs->group_desc[i].bg_block_bitmap = 0; | |
411 | ctx->invalid_block_bitmap_flag[i]++; | |
412 | ctx->invalid_bitmaps++; | |
413 | } | |
414 | } | |
415 | if ((fs->group_desc[i].bg_inode_bitmap < first_block) || | |
416 | (fs->group_desc[i].bg_inode_bitmap >= last_block)) { | |
417 | pctx.blk = fs->group_desc[i].bg_inode_bitmap; | |
418 | if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) { | |
419 | fs->group_desc[i].bg_inode_bitmap = 0; | |
420 | ctx->invalid_inode_bitmap_flag[i]++; | |
421 | ctx->invalid_bitmaps++; | |
422 | } | |
423 | } | |
424 | if ((fs->group_desc[i].bg_inode_table < first_block) || | |
425 | ((fs->group_desc[i].bg_inode_table + | |
426 | fs->inode_blocks_per_group - 1) >= last_block)) { | |
427 | pctx.blk = fs->group_desc[i].bg_inode_table; | |
428 | if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) { | |
429 | fs->group_desc[i].bg_inode_table = 0; | |
430 | ctx->invalid_inode_table_flag[i]++; | |
431 | ctx->invalid_bitmaps++; | |
432 | } | |
433 | } | |
434 | first_block += fs->super->s_blocks_per_group; | |
435 | last_block += fs->super->s_blocks_per_group; | |
436 | } | |
437 | /* | |
438 | * If we have invalid bitmaps, set the error state of the | |
439 | * filesystem. | |
440 | */ | |
441 | if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) { | |
442 | fs->super->s_state &= ~EXT2_VALID_FS; | |
443 | ext2fs_mark_super_dirty(fs); | |
444 | } | |
445 | ||
4ea0a110 TT |
446 | clear_problem_context(&pctx); |
447 | ||
54be2ccc | 448 | #ifndef EXT2_SKIP_UUID |
1b6bf175 TT |
449 | /* |
450 | * If the UUID field isn't assigned, assign it. | |
451 | */ | |
5dd8f963 | 452 | if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) { |
1b6bf175 | 453 | if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) { |
5dd8f963 | 454 | uuid_generate(sb->s_uuid); |
1b6bf175 TT |
455 | ext2fs_mark_super_dirty(fs); |
456 | } | |
457 | } | |
54be2ccc | 458 | #endif |
4ea0a110 TT |
459 | |
460 | /* | |
461 | * For the Hurd, check to see if the filetype option is set, | |
462 | * since it doesn't support it. | |
463 | */ | |
80bfaa3e TT |
464 | if (!(ctx->options & E2F_OPT_READONLY) && |
465 | fs->super->s_creator_os == EXT2_OS_HURD && | |
4ea0a110 TT |
466 | (fs->super->s_feature_incompat & |
467 | EXT2_FEATURE_INCOMPAT_FILETYPE)) { | |
468 | if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) { | |
469 | fs->super->s_feature_incompat &= | |
470 | ~EXT2_FEATURE_INCOMPAT_FILETYPE; | |
471 | ext2fs_mark_super_dirty(fs); | |
472 | ||
473 | } | |
474 | } | |
80bfaa3e | 475 | |
7b59f1ef TT |
476 | /* |
477 | * If we have any of the compatibility flags set, we need to have a | |
478 | * revision 1 filesystem. Most kernels will not check the flags on | |
479 | * a rev 0 filesystem and we may have corruption issues because of | |
480 | * the incompatible changes to the filesystem. | |
481 | */ | |
482 | if (!(ctx->options & E2F_OPT_READONLY) && | |
483 | fs->super->s_rev_level == EXT2_GOOD_OLD_REV && | |
484 | (fs->super->s_feature_compat || | |
485 | fs->super->s_feature_ro_compat || | |
486 | fs->super->s_feature_incompat) && | |
487 | fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) { | |
a917d1cc | 488 | ext2fs_update_dynamic_rev(fs); |
7b59f1ef TT |
489 | ext2fs_mark_super_dirty(fs); |
490 | } | |
491 | ||
80bfaa3e TT |
492 | /* |
493 | * Clean up any orphan inodes, if present. | |
494 | */ | |
495 | if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) { | |
496 | fs->super->s_state &= ~EXT2_VALID_FS; | |
7b59f1ef | 497 | ext2fs_mark_super_dirty(fs); |
80bfaa3e TT |
498 | } |
499 | ||
1b6bf175 TT |
500 | return; |
501 | } | |
80bfaa3e TT |
502 | |
503 |