summaryrefslogtreecommitdiff
path: root/e2fsck/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'e2fsck/super.c')
-rw-r--r--e2fsck/super.c51
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)))