]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/super.c
Fix resize2fs so that it properly handles filesystems with the resize_inode
[thirdparty/e2fsprogs.git] / e2fsck / super.c
CommitLineData
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
25static 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
46errcode_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 */
57struct 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;
54434927 63 e2_blkcnt_t truncate_block;
8394902e
TT
64 int truncated_blocks;
65 int abort;
66 errcode_t errcode;
80bfaa3e
TT
67};
68
69static int release_inode_block(ext2_filsys fs,
70 blk_t *block_nr,
54434927
TT
71 e2_blkcnt_t blockcnt,
72 blk_t ref_blk EXT2FS_ATTR((unused)),
73 int ref_offset EXT2FS_ATTR((unused)),
80bfaa3e
TT
74 void *priv_data)
75{
76 struct process_block_struct *pb;
8394902e
TT
77 e2fsck_t ctx;
78 struct problem_context *pctx;
79 blk_t blk = *block_nr;
80 int retval = 0;
80bfaa3e
TT
81
82 pb = (struct process_block_struct *) priv_data;
83 ctx = pb->ctx;
84 pctx = pb->pctx;
85
86 pctx->blk = blk;
87 pctx->blkcount = blockcnt;
88
89 if (HOLE_BLKADDR(blk))
90 return 0;
91
92 if ((blk < fs->super->s_first_data_block) ||
93 (blk >= fs->super->s_blocks_count)) {
94 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
53ef44c4 95 return_abort:
80bfaa3e
TT
96 pb->abort = 1;
97 return BLOCK_ABORT;
98 }
99
100 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
101 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
53ef44c4 102 goto return_abort;
8394902e
TT
103 }
104
105 /*
106 * If we are deleting an orphan, then we leave the fields alone.
107 * If we are truncating an orphan, then update the inode fields
108 * and clean up any partial block data.
109 */
110 if (pb->truncating) {
111 /*
112 * We only remove indirect blocks if they are
113 * completely empty.
114 */
115 if (blockcnt < 0) {
116 int i, limit;
53ef44c4 117 blk_t *bp;
8394902e
TT
118
119 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
120 pb->buf);
121 if (pb->errcode)
53ef44c4 122 goto return_abort;
8394902e
TT
123
124 limit = fs->blocksize >> 2;
53ef44c4
TT
125 for (i = 0, bp = (blk_t *) pb->buf;
126 i < limit; i++, bp++)
127 if (*bp)
8394902e
TT
128 return 0;
129 }
130 /*
131 * We don't remove direct blocks until we've reached
132 * the truncation block.
133 */
134 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
135 return 0;
136 /*
137 * If part of the last block needs truncating, we do
138 * it here.
139 */
140 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
141 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
142 pb->buf);
143 if (pb->errcode)
53ef44c4 144 goto return_abort;
8394902e
TT
145 memset(pb->buf + pb->truncate_offset, 0,
146 fs->blocksize - pb->truncate_offset);
147 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
148 pb->buf);
149 if (pb->errcode)
53ef44c4 150 goto return_abort;
8394902e
TT
151 }
152 pb->truncated_blocks++;
153 *block_nr = 0;
154 retval |= BLOCK_CHANGED;
80bfaa3e
TT
155 }
156
0684a4f3 157 ext2fs_block_alloc_stats(fs, blk, -1);
8394902e 158 return retval;
80bfaa3e
TT
159}
160
161/*
162 * This function releases an inode. Returns 1 if an inconsistency was
8394902e
TT
163 * found. If the inode has a link count, then it is being truncated and
164 * not deleted.
80bfaa3e 165 */
86c627ec 166static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
721edd0e 167 struct ext2_inode *inode, char *block_buf,
80bfaa3e
TT
168 struct problem_context *pctx)
169{
0684a4f3 170 struct process_block_struct pb;
8394902e 171 ext2_filsys fs = ctx->fs;
80bfaa3e 172 errcode_t retval;
0684a4f3 173 __u32 count;
80bfaa3e 174
42475e28
TT
175 if (!ext2fs_inode_has_valid_blocks(inode))
176 return 0;
177
8394902e 178 pb.buf = block_buf + 3 * ctx->fs->blocksize;
80bfaa3e
TT
179 pb.ctx = ctx;
180 pb.abort = 0;
8394902e 181 pb.errcode = 0;
80bfaa3e 182 pb.pctx = pctx;
8394902e
TT
183 if (inode->i_links_count) {
184 pb.truncating = 1;
54434927 185 pb.truncate_block = (e2_blkcnt_t)
8394902e
TT
186 ((((long long)inode->i_size_high << 32) +
187 inode->i_size + fs->blocksize - 1) /
188 fs->blocksize);
189 pb.truncate_offset = inode->i_size % fs->blocksize;
190 } else {
191 pb.truncating = 0;
192 pb.truncate_block = 0;
193 pb.truncate_offset = 0;
194 }
195 pb.truncated_blocks = 0;
54434927 196 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
8394902e 197 block_buf, release_inode_block, &pb);
80bfaa3e 198 if (retval) {
8394902e 199 com_err("release_inode_blocks", retval,
80bfaa3e
TT
200 _("while calling ext2fs_block_iterate for inode %d"),
201 ino);
202 return 1;
203 }
204 if (pb.abort)
205 return 1;
206
8394902e
TT
207 /* Refresh the inode since ext2fs_block_iterate may have changed it */
208 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
209
210 if (pb.truncated_blocks)
211 inode->i_blocks -= pb.truncated_blocks *
212 (fs->blocksize / 512);
213
0684a4f3
TT
214 if (inode->i_file_acl) {
215 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
216 block_buf, -1, &count);
217 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
218 retval = 0;
219 count = 1;
220 }
221 if (retval) {
222 com_err("release_inode_blocks", retval,
223 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
224 ino);
225 return 1;
226 }
227 if (count == 0)
228 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
229 inode->i_file_acl = 0;
230 }
80bfaa3e
TT
231 return 0;
232}
233
234/*
235 * This function releases all of the orphan inodes. It returns 1 if
236 * it hit some error, and 0 on success.
237 */
238static int release_orphan_inodes(e2fsck_t ctx)
239{
240 ext2_filsys fs = ctx->fs;
86c627ec 241 ext2_ino_t ino, next_ino;
80bfaa3e
TT
242 struct ext2_inode inode;
243 struct problem_context pctx;
244 char *block_buf;
245
246 if ((ino = fs->super->s_last_orphan) == 0)
247 return 0;
248
25c63ba0
TT
249 /*
250 * Win or lose, we won't be using the head of the orphan inode
251 * list again.
252 */
253 fs->super->s_last_orphan = 0;
254 ext2fs_mark_super_dirty(fs);
eb4ab510
TT
255
256 /*
257 * If the filesystem contains errors, don't run the orphan
258 * list, since the orphan list can't be trusted; and we're
259 * going to be running a full e2fsck run anyway...
260 */
261 if (fs->super->s_state & EXT2_ERROR_FS)
262 return 0;
25c63ba0 263
80bfaa3e
TT
264 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
265 (ino > fs->super->s_inodes_count)) {
266 clear_problem_context(&pctx);
53ef44c4 267 pctx.ino = ino;
80bfaa3e
TT
268 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
269 return 1;
270 }
271
8394902e 272 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
9b565759 273 "block iterate buffer");
80bfaa3e
TT
274 e2fsck_read_bitmaps(ctx);
275
276 while (ino) {
8394902e 277 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
80bfaa3e 278 clear_problem_context(&pctx);
ecf1b776 279 pctx.ino = ino;
80bfaa3e 280 pctx.inode = &inode;
f0b8c87d
TT
281 pctx.str = inode.i_links_count ? _("Truncating") :
282 _("Clearing");
80bfaa3e 283
8394902e 284 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
ecf1b776 285
80bfaa3e
TT
286 next_ino = inode.i_dtime;
287 if (next_ino &&
99a2cc96
TT
288 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
289 (next_ino > fs->super->s_inodes_count))) {
290 pctx.ino = next_ino;
80bfaa3e 291 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
53ef44c4 292 goto return_abort;
80bfaa3e
TT
293 }
294
8394902e 295 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
53ef44c4 296 goto return_abort;
ecf1b776 297
8394902e 298 if (!inode.i_links_count) {
0684a4f3
TT
299 ext2fs_inode_alloc_stats2(fs, ino, -1,
300 LINUX_S_ISDIR(inode.i_mode));
8394902e 301 inode.i_dtime = time(0);
eb16f861
ST
302 } else {
303 inode.i_dtime = 0;
8394902e
TT
304 }
305 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
80bfaa3e
TT
306 ino = next_ino;
307 }
c4e3d3f3 308 ext2fs_free_mem(&block_buf);
80bfaa3e 309 return 0;
53ef44c4 310return_abort:
c4e3d3f3 311 ext2fs_free_mem(&block_buf);
80bfaa3e
TT
312 return 1;
313}
314
315
1b6bf175
TT
316void check_super_block(e2fsck_t ctx)
317{
318 ext2_filsys fs = ctx->fs;
319 blk_t first_block, last_block;
5dd8f963 320 struct ext2_super_block *sb = fs->super;
1b6bf175 321 blk_t blocks_per_group = fs->super->s_blocks_per_group;
b21bf267 322 blk_t bpg_max;
78cf0547 323 int inodes_per_block;
b21bf267 324 int ipg_max;
7f813ba3 325 dgrp_t i;
1b6bf175
TT
326 blk_t should_be;
327 struct problem_context pctx;
e75cfc5d 328 struct ext2_inode inode;
2a77a784 329 __u32 free_blocks = 0, free_inodes = 0;
b21bf267
AD
330
331 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
332 ipg_max = inodes_per_block * (blocks_per_group - 4);
333 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
334 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
335 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
336 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
337 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
1b6bf175 338
54dc7ca2 339 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
f8188fff 340 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
54dc7ca2 341 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
f8188fff 342 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
54dc7ca2 343 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
f8188fff 344 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
b21bf267 345
1b6bf175
TT
346 clear_problem_context(&pctx);
347
348 /*
349 * Verify the super block constants...
350 */
5dd8f963 351 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
1b6bf175 352 MIN_CHECK, 1, 0);
5dd8f963 353 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
1b6bf175 354 MIN_CHECK, 1, 0);
5dd8f963
TT
355 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
356 MAX_CHECK, 0, sb->s_blocks_count);
5dd8f963 357 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
31e29a12
TT
358 MIN_CHECK | MAX_CHECK, 0,
359 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
932a489c
AD
360 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
361 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
5dd8f963 362 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
ef059870 363 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
b21bf267 364 bpg_max);
5dd8f963 365 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
b21bf267 366 MIN_CHECK | MAX_CHECK, 8, bpg_max);
5dd8f963 367 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
b21bf267 368 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
5dd8f963 369 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
424cd2be 370 MAX_CHECK, 0, sb->s_blocks_count / 4);
1b6bf175 371
f8188fff 372 if (!ctx->num_blocks) {
4313932c 373 pctx.errcode = e2fsck_get_device_size(ctx);
f8188fff
TT
374 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
375 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
08b21301
TT
376 ctx->flags |= E2F_FLAG_ABORT;
377 return;
378 }
f8188fff 379 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
5dd8f963
TT
380 (ctx->num_blocks < sb->s_blocks_count)) {
381 pctx.blk = sb->s_blocks_count;
f8188fff
TT
382 pctx.blk2 = ctx->num_blocks;
383 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
384 ctx->flags |= E2F_FLAG_ABORT;
385 return;
386 }
387 }
1b6bf175
TT
388 }
389
54434927 390 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
5dd8f963
TT
391 pctx.blk = EXT2_BLOCK_SIZE(sb);
392 pctx.blk2 = EXT2_FRAG_SIZE(sb);
1b6bf175 393 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
08b21301
TT
394 ctx->flags |= E2F_FLAG_ABORT;
395 return;
1b6bf175
TT
396 }
397
5dd8f963
TT
398 should_be = sb->s_frags_per_group >>
399 (sb->s_log_block_size - sb->s_log_frag_size);
400 if (sb->s_blocks_per_group != should_be) {
401 pctx.blk = sb->s_blocks_per_group;
1b6bf175
TT
402 pctx.blk2 = should_be;
403 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
08b21301
TT
404 ctx->flags |= E2F_FLAG_ABORT;
405 return;
1b6bf175
TT
406 }
407
5dd8f963
TT
408 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
409 if (sb->s_first_data_block != should_be) {
410 pctx.blk = sb->s_first_data_block;
1b6bf175
TT
411 pctx.blk2 = should_be;
412 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
08b21301
TT
413 ctx->flags |= E2F_FLAG_ABORT;
414 return;
1b6bf175
TT
415 }
416
5dd8f963
TT
417 should_be = sb->s_inodes_per_group * fs->group_desc_count;
418 if (sb->s_inodes_count != should_be) {
419 pctx.ino = sb->s_inodes_count;
d4b0ce03
TT
420 pctx.ino2 = should_be;
421 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
5dd8f963 422 sb->s_inodes_count = should_be;
d4b0ce03
TT
423 ext2fs_mark_super_dirty(fs);
424 }
425 }
426
1b6bf175
TT
427 /*
428 * Verify the group descriptors....
429 */
430 first_block = fs->super->s_first_data_block;
431 last_block = first_block + blocks_per_group;
432
433 for (i = 0; i < fs->group_desc_count; i++) {
434 pctx.group = i;
435
436 if (i == fs->group_desc_count - 1)
437 last_block = fs->super->s_blocks_count;
438 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
439 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
440 pctx.blk = fs->group_desc[i].bg_block_bitmap;
24bfb443 441 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
1b6bf175 442 fs->group_desc[i].bg_block_bitmap = 0;
24bfb443
TT
443 }
444 if (fs->group_desc[i].bg_block_bitmap == 0) {
445 ctx->invalid_block_bitmap_flag[i]++;
446 ctx->invalid_bitmaps++;
1b6bf175
TT
447 }
448 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
449 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
450 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
24bfb443 451 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
1b6bf175 452 fs->group_desc[i].bg_inode_bitmap = 0;
24bfb443
TT
453 }
454 if (fs->group_desc[i].bg_inode_bitmap == 0) {
455 ctx->invalid_inode_bitmap_flag[i]++;
456 ctx->invalid_bitmaps++;
1b6bf175
TT
457 }
458 if ((fs->group_desc[i].bg_inode_table < first_block) ||
459 ((fs->group_desc[i].bg_inode_table +
460 fs->inode_blocks_per_group - 1) >= last_block)) {
461 pctx.blk = fs->group_desc[i].bg_inode_table;
24bfb443 462 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
1b6bf175 463 fs->group_desc[i].bg_inode_table = 0;
24bfb443
TT
464 }
465 if (fs->group_desc[i].bg_inode_table == 0) {
466 ctx->invalid_inode_table_flag[i]++;
467 ctx->invalid_bitmaps++;
1b6bf175 468 }
2a77a784
TT
469 free_blocks += fs->group_desc[i].bg_free_blocks_count;
470 free_inodes += fs->group_desc[i].bg_free_inodes_count;
1b6bf175
TT
471 first_block += fs->super->s_blocks_per_group;
472 last_block += fs->super->s_blocks_per_group;
473 }
474 /*
475 * If we have invalid bitmaps, set the error state of the
476 * filesystem.
477 */
478 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
479 fs->super->s_state &= ~EXT2_VALID_FS;
480 ext2fs_mark_super_dirty(fs);
481 }
482
4ea0a110
TT
483 clear_problem_context(&pctx);
484
54be2ccc 485#ifndef EXT2_SKIP_UUID
1b6bf175
TT
486 /*
487 * If the UUID field isn't assigned, assign it.
488 */
5dd8f963 489 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
1b6bf175 490 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
5dd8f963 491 uuid_generate(sb->s_uuid);
1b6bf175 492 ext2fs_mark_super_dirty(fs);
299d7424 493 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
1b6bf175
TT
494 }
495 }
54be2ccc 496#endif
2a77a784
TT
497
498 /*
499 * Update the global counts from the block group counts. This
500 * is needed for an experimental patch which eliminates
501 * locking the entire filesystem when allocating blocks or
502 * inodes; if the filesystem is not unmounted cleanly, the
503 * global counts may not be accurate.
504 */
505 if (!(ctx->options & E2F_OPT_READONLY) &&
506 ((free_blocks != fs->super->s_free_blocks_count) ||
507 (free_inodes != fs->super->s_free_inodes_count))) {
508 fs->super->s_free_blocks_count = free_blocks;
509 fs->super->s_free_inodes_count = free_inodes;
510 ext2fs_mark_super_dirty(fs);
511 }
4ea0a110
TT
512
513 /*
514 * For the Hurd, check to see if the filetype option is set,
515 * since it doesn't support it.
516 */
80bfaa3e
TT
517 if (!(ctx->options & E2F_OPT_READONLY) &&
518 fs->super->s_creator_os == EXT2_OS_HURD &&
4ea0a110
TT
519 (fs->super->s_feature_incompat &
520 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
521 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
522 fs->super->s_feature_incompat &=
523 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
524 ext2fs_mark_super_dirty(fs);
525
526 }
527 }
80bfaa3e 528
7b59f1ef
TT
529 /*
530 * If we have any of the compatibility flags set, we need to have a
531 * revision 1 filesystem. Most kernels will not check the flags on
532 * a rev 0 filesystem and we may have corruption issues because of
533 * the incompatible changes to the filesystem.
534 */
535 if (!(ctx->options & E2F_OPT_READONLY) &&
536 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
537 (fs->super->s_feature_compat ||
538 fs->super->s_feature_ro_compat ||
539 fs->super->s_feature_incompat) &&
540 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
a917d1cc 541 ext2fs_update_dynamic_rev(fs);
7b59f1ef
TT
542 ext2fs_mark_super_dirty(fs);
543 }
544
e75cfc5d
TT
545 /*
546 * If the resize inode feature isn't set, then
547 * s_reserved_gdt_blocks must be zero, and the resize inode
548 * must be cleared.
549 */
550 if (!(fs->super->s_feature_compat &
551 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
552 if (fs->super->s_reserved_gdt_blocks) {
553 pctx.num = fs->super->s_reserved_gdt_blocks;
554 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
555 &pctx)) {
556 fs->super->s_reserved_gdt_blocks = 0;
557 ext2fs_mark_super_dirty(fs);
558 }
559 }
560 e2fsck_read_inode(ctx, EXT2_RESIZE_INO, &inode,
561 "check_resize");
562 for (i=0; i < EXT2_N_BLOCKS; i++) {
563 if (inode.i_block[i])
564 break;
565 }
566 pctx.ino = EXT2_RESIZE_INO;
567 if ((i < EXT2_N_BLOCKS) &&
568 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
569 for (i=0; i < EXT2_N_BLOCKS; i++) {
570 inode.i_block[i] = 0;
571 }
572 inode.i_blocks = 0;
573 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
574 "clear_resize");
575 }
576 }
577
80bfaa3e
TT
578 /*
579 * Clean up any orphan inodes, if present.
580 */
581 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
582 fs->super->s_state &= ~EXT2_VALID_FS;
7b59f1ef 583 ext2fs_mark_super_dirty(fs);
80bfaa3e
TT
584 }
585
773fd8a1
TT
586 /*
587 * Move the ext3 journal file, if necessary.
588 */
589 e2fsck_move_ext3_journal(ctx);
1b6bf175
TT
590 return;
591}