diff options
Diffstat (limited to 'e2fsck/super.c')
-rw-r--r-- | e2fsck/super.c | 51 |
1 files changed, 34 insertions, 17 deletions
diff --git a/e2fsck/super.c b/e2fsck/super.c index 6c18d0ef..81503d4b 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -22,6 +22,7 @@ #define MIN_CHECK 1 #define MAX_CHECK 2 +#define LOG2_CHECK 4 static void check_super_value(e2fsck_t ctx, const char *descr, unsigned long value, int flags, @@ -29,8 +30,9 @@ static void check_super_value(e2fsck_t ctx, const char *descr, { struct problem_context pctx; - if (((flags & MIN_CHECK) && (value < min_val)) || - ((flags & MAX_CHECK) && (value > max_val))) { + if ((flags & MIN_CHECK && value < min_val) || + (flags & MAX_CHECK && value > max_val) || + (flags & LOG2_CHECK && (value & (value - 1)) != 0)) { clear_problem_context(&pctx); pctx.num = value; pctx.str = descr; @@ -143,6 +145,7 @@ static int release_inode_block(ext2_filsys fs, } ext2fs_block_alloc_stats2(fs, blk, -1); + ctx->free_blocks++; return retval; } @@ -211,9 +214,11 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, ino); return 1; } - if (count == 0) + if (count == 0) { ext2fs_block_alloc_stats2(fs, ext2fs_file_acl_block(fs, inode), -1); + ctx->free_blocks++; + } ext2fs_file_acl_block_set(fs, inode, 0); } return 0; @@ -286,6 +291,7 @@ static int release_orphan_inodes(e2fsck_t ctx) if (!inode.i_links_count) { ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); + ctx->free_inodes++; inode.i_dtime = ctx->now; } else { inode.i_dtime = 0; @@ -313,7 +319,8 @@ void check_resize_inode(e2fsck_t ctx) struct problem_context pctx; int i, gdt_off, ind_off; dgrp_t j; - blk64_t blk, pblk, expect; + blk_t blk, pblk; + blk_t expect; /* for resize inode, which is 32-bit only */ __u32 *dind_buf = 0, *ind_buf; errcode_t retval; @@ -460,11 +467,11 @@ void check_super_block(e2fsck_t ctx) ext2_filsys fs = ctx->fs; blk64_t first_block, last_block; struct ext2_super_block *sb = fs->super; + unsigned int ipg_max; problem_t problem; blk64_t blocks_per_group = fs->super->s_blocks_per_group; __u32 bpg_max, cpg_max; int inodes_per_block; - int ipg_max; int inode_size; int accept_time_fudge; int broken_system_clock; @@ -522,14 +529,17 @@ void check_super_block(e2fsck_t ctx) MAX_CHECK, 0, ext2fs_blocks_count(sb) / 2); check_super_value(ctx, "reserved_gdt_blocks", sb->s_reserved_gdt_blocks, MAX_CHECK, 0, - fs->blocksize/4); + fs->blocksize / sizeof(__u32)); + check_super_value(ctx, "desc_size", + sb->s_desc_size, MAX_CHECK | LOG2_CHECK, 0, + EXT2_MAX_DESC_SIZE); if (sb->s_rev_level > EXT2_GOOD_OLD_REV) check_super_value(ctx, "first_ino", sb->s_first_ino, MIN_CHECK | MAX_CHECK, EXT2_GOOD_OLD_FIRST_INO, sb->s_inodes_count); inode_size = EXT2_INODE_SIZE(sb); check_super_value(ctx, "inode_size", - inode_size, MIN_CHECK | MAX_CHECK, + inode_size, MIN_CHECK | MAX_CHECK | LOG2_CHECK, EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize); if (sb->s_blocks_per_group != (sb->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs))) { @@ -539,13 +549,6 @@ void check_super_block(e2fsck_t ctx) ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ return; } - if (inode_size & (inode_size - 1)) { - pctx.num = inode_size; - pctx.str = "inode_size"; - fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); - ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ - return; - } if ((ctx->flags & E2F_FLAG_GOT_DEVSIZE) && (ctx->num_blocks < ext2fs_blocks_count(sb))) { @@ -577,6 +580,17 @@ void check_super_block(e2fsck_t ctx) } } + /* Is 64bit set and extents unset? */ + if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, + EXT4_FEATURE_INCOMPAT_64BIT) && + !EXT2_HAS_INCOMPAT_FEATURE(fs->super, + EXT3_FEATURE_INCOMPAT_EXTENTS) && + fix_problem(ctx, PR_0_64BIT_WITHOUT_EXTENTS, &pctx)) { + fs->super->s_feature_incompat |= + EXT3_FEATURE_INCOMPAT_EXTENTS; + ext2fs_mark_super_dirty(fs); + } + /* * Verify the group descriptors.... */ @@ -708,8 +722,11 @@ void check_super_block(e2fsck_t ctx) #ifndef EXT2_SKIP_UUID /* * If the UUID field isn't assigned, assign it. + * Skip if checksums are enabled and the filesystem is mounted, + * if the id changes under the kernel remounting rw may fail. */ - if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) { + if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid) && + (!csum_flag || !(ctx->mount_flags & EXT2_MF_MOUNTED))) { if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) { uuid_generate(sb->s_uuid); fs->flags |= EXT2_FLAG_DIRTY; @@ -910,8 +927,7 @@ int check_backup_super_block(e2fsck_t ctx) if (!ext2fs_bg_has_super(fs, g)) continue; - sb = fs->super->s_first_data_block + - (g * fs->super->s_blocks_per_group); + sb = ext2fs_group_first_block2(fs, g); retval = io_channel_read_blk(fs->io, sb, -SUPERBLOCK_SIZE, buf); @@ -941,6 +957,7 @@ int check_backup_super_block(e2fsck_t ctx) SUPER_INCOMPAT_DIFFERENT(s_feature_incompat) || SUPER_RO_COMPAT_DIFFERENT(s_feature_ro_compat) || SUPER_DIFFERENT(s_blocks_count) || + SUPER_DIFFERENT(s_blocks_count_hi) || SUPER_DIFFERENT(s_inodes_count) || memcmp(fs->super->s_uuid, backup_sb->s_uuid, sizeof(fs->super->s_uuid))) |