From: Theodore Ts'o Date: Tue, 24 Mar 1998 16:22:38 +0000 (+0000) Subject: Many files: X-Git-Tag: E2FSPROGS-1_12~41 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=246501c612cb8309dc81b354b785405bbeef05ce;p=tools%2Fe2fsprogs.git Many files: unix.c: Fix bug in check of feature set, to make sure we can really fix this filesystem. problem.h: Make blkcount type to be of type blkcnt_t. Make the num field be a 64 bit type. Add the problem code PR_1_FEATURE_LARGE_FILES problem.c: Add table entry for the problem code PR_1_FEATURE_LARGE_FILES. pass1.c (e2fsck_pass1): A non-zero i_dir_acl field is only a problem for directory inodes. (Since it is also i_size_high now.) If there are no large_files, then clear the LARGE_FLAG feature flag. If there are large_files, but the LARGE_FLAG feature flag is not set, complain and offer to fix it. (check_blocks): Add support to deal with non-directory inodes that have i_size_high set (i.e., large_files). Don't give an error if a directory has preallocated blocks, to support the DIR_PREALLOC feature. (process_block, process_bad_block): The blockcnt variable is a type of blkcnt_t, for conversion to the new block_iterate2. pass2.c (process_bad_inode): A non-zero i_dir_acl field is only a problem for directory inodes. (Since it is also i_size_high now.) message.c (expand_inode_expression): Print a 64-bits of the inode size for non-directory inodes. (Directory inodes can only use a 32-bit directory acl size, since i_size_high is shared with i_dir_acl.) Add sanity check so that trying to print out the directory acl on a non-directory inode will print zero. (expand_percent_expression): %B and %N, which print pctx->blkcount and pctx->num, can now be 64 bit variables. Print them using the "%lld" format if EXT2_NO_64_TYPE is not defined. e2fsck.h: Add the large_flagsfield to the e2fsck context. e2fsck.c (e2fsck_reset_context): Clear the large_flags field. ChangeLog, expect.1: f_messy_inode: Modify test to deal with changes to support 64-bit size files. (/MAKEDEV had i_dir_acl, now i_size_high, set.) --- diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index 0d0ef86..4d7b72f 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,49 @@ +1998-03-23 Theodore Ts'o + + * unix.c: Fix bug in check of feature set, to make sure we can + really fix this filesystem. + + * problem.h: Make blkcount type to be of type blkcnt_t. Make the + num field be a 64 bit type. Add the problem code + PR_1_FEATURE_LARGE_FILES + + * problem.c: Add table entry for the problem code + PR_1_FEATURE_LARGE_FILES. + + * pass1.c (e2fsck_pass1): A non-zero i_dir_acl field is only + a problem for directory inodes. (Since it is also + i_size_high now.) If there are no large_files, then + clear the LARGE_FLAG feature flag. If there are + large_files, but the LARGE_FLAG feature flag is not set, + complain and offer to fix it. + (check_blocks): Add support to deal with non-directory + inodes that have i_size_high set (i.e., large_files). + Don't give an error if a directory has preallocated + blocks, to support the DIR_PREALLOC feature. + (process_block, process_bad_block): The blockcnt variable + is a type of blkcnt_t, for conversion to the new + block_iterate2. + + * pass2.c (process_bad_inode): A non-zero i_dir_acl field is only + a problem for directory inodes. (Since it is also + i_size_high now.) + + * message.c (expand_inode_expression): Print a 64-bits of the + inode size for non-directory inodes. (Directory inodes + can only use a 32-bit directory acl size, since + i_size_high is shared with i_dir_acl.) Add sanity check + so that trying to print out the directory acl on a + non-directory inode will print zero. + (expand_percent_expression): %B and %N, which print + pctx->blkcount and pctx->num, can now be 64 bit + variables. Print them using the "%lld" format if + EXT2_NO_64_TYPE is not defined. + + * e2fsck.h: Add the large_flagsfield to the e2fsck context. + + * e2fsck.c (e2fsck_reset_context): Clear the large_flags + field. + Sun Mar 8 23:08:08 1998 Theodore Ts'o * pass3.c (fix_dotdot_proc): diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c index 56437d5..41195fe 100644 --- a/e2fsck/e2fsck.c +++ b/e2fsck/e2fsck.c @@ -108,6 +108,7 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx) ctx->fs_dind_count = 0; ctx->fs_tind_count = 0; ctx->fs_fragmented = 0; + ctx->large_files = 0; /* Reset the superblock to the user's requested value */ ctx->superblock = ctx->use_superblock; diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index b8ac30c..e1c5944 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -205,6 +205,7 @@ struct e2fsck_struct { int fs_dind_count; int fs_tind_count; int fs_fragmented; + int large_files; /* * For the use of callers of the e2fsck functions; not used by diff --git a/e2fsck/message.c b/e2fsck/message.c index 82cb423..c839bbf 100644 --- a/e2fsck/message.c +++ b/e2fsck/message.c @@ -197,7 +197,20 @@ static _INLINE_ void expand_inode_expression(char ch, switch (ch) { case 's': - printf("%u", inode->i_size); + if (LINUX_S_ISDIR(inode->i_mode)) + printf("%u", inode->i_size); + else { +#ifdef EXT2_NO_64_TYPE + if (inode->i_size_high) + printf("0x%x%08x", inode->i_size_high, + inode->i_size); + else + printf("%u", inode->i_size); +#else + printf("%llu", (inode->i_size | + ((__u64) inode->i_size_high << 32))); +#endif + } break; case 'b': printf("%u", inode->i_blocks); @@ -220,7 +233,8 @@ static _INLINE_ void expand_inode_expression(char ch, printf("%u", inode->i_file_acl); break; case 'd': - printf("%u", inode->i_dir_acl); + printf("%u", (LINUX_S_ISDIR(inode->i_mode) ? + inode->i_dir_acl : 0)); break; default: no_inode: @@ -282,7 +296,11 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, printf("%u", ctx->blk); break; case 'B': +#ifdef EXT2_NO_64_TYPE printf("%d", ctx->blkcount); +#else + printf("%lld", ctx->blkcount); +#endif break; case 'c': printf("%u", ctx->blk2); @@ -303,7 +321,11 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, printf("%s", error_message(ctx->errcode)); break; case 'N': +#ifdef EXT2_NO_64_TYPE printf("%u", ctx->num); +#else + printf("%llu", ctx->num); +#endif break; case 'p': print_pathname(fs, ctx->ino, 0); diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index e2a35f0..7ba9c63 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -50,10 +50,10 @@ #endif static int process_block(ext2_filsys fs, blk_t *blocknr, - int blockcnt, blk_t ref_blk, + blkcnt_t blockcnt, blk_t ref_blk, int ref_offset, void *priv_data); static int process_bad_block(ext2_filsys fs, blk_t *block_nr, - int blockcnt, blk_t ref_blk, + blkcnt_t blockcnt, blk_t ref_blk, int ref_offset, void *priv_data); static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, char *block_buf); @@ -68,12 +68,12 @@ static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, /* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */ struct process_block_struct { - ino_t ino; - int is_dir:1, clear:1, suppress:1, fragmented:1; - int num_blocks; - int last_block; - int num_illegal_blocks; - blk_t previous_block; + ino_t ino; + int is_dir:1, clear:1, suppress:1, fragmented:1; + blk_t num_blocks; + blkcnt_t last_block; + int num_illegal_blocks; + blk_t previous_block; struct ext2_inode *inode; struct problem_context *pctx; e2fsck_t ctx; @@ -95,6 +95,20 @@ struct scan_callback_struct { static struct process_inode_block *inodes_to_process; static int process_inode_count; +#define EXT2_BPP(bits) (1UL << ((bits) - 2)) + +#define EXT2_MAX_SIZE(bits) \ + (((EXT2_NDIR_BLOCKS + EXT2_BPP(bits) + \ + EXT2_BPP(bits) * EXT2_BPP(bits) + \ + EXT2_BPP(bits) * EXT2_BPP(bits) * EXT2_BPP(bits)) * \ + (1UL << bits)) - 1) + +static long long ext2_max_sizes[] = { +EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13) +}; + +#undef EXT2_BPP + /* * Free all memory allocated by pass1 in preparation for restarting * things. @@ -382,7 +396,8 @@ void e2fsck_pass1(e2fsck_t ctx) } if (inode.i_faddr || frag || fsize - || inode.i_file_acl || inode.i_dir_acl) { + || inode.i_file_acl || + (LINUX_S_ISDIR(inode.i_mode) && inode.i_dir_acl)) { if (!ctx->inode_bad_map) alloc_bad_map(ctx); ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); @@ -487,6 +502,24 @@ endit: ext2fs_free_block_bitmap(ctx->block_illegal_map); ctx->block_illegal_map = 0; + if (ctx->large_files && + !(fs->super->s_feature_ro_compat & + EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { + if (fix_problem(ctx, PR_1_FEATURE_LARGE_FILES, &pctx)) { + fs->super->s_feature_ro_compat |= + EXT2_FEATURE_RO_COMPAT_LARGE_FILE; + ext2fs_mark_super_dirty(fs); + } + } else if (!ctx->large_files && + (fs->super->s_feature_ro_compat & + EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { + if (fs->flags & EXT2_FLAG_RW) { + fs->super->s_feature_ro_compat &= + ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE; + ext2fs_mark_super_dirty(fs); + } + } + #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) print_resource_track("Pass 1", &rtrack); @@ -654,6 +687,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, struct process_block_struct pb; ino_t ino = pctx->ino; struct ext2_inode *inode = pctx->inode; + int bad_size = 0; + __u64 size; + struct ext2fs_sb *sb; if (!ext2fs_inode_has_valid_blocks(pctx->inode)) return; @@ -700,7 +736,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, pb.num_blocks *= (fs->blocksize / 512); #if 0 - printf("inode %u, i_size = %lu, last_block = %lu, i_blocks=%lu, num_blocks = %lu\n", + printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n", ino, inode->i_size, pb.last_block, inode->i_blocks, pb.num_blocks); #endif @@ -716,16 +752,36 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, pb.is_dir = 0; } } - if ((pb.is_dir && (inode->i_size != - (pb.last_block + 1) * fs->blocksize)) || - (inode->i_size < pb.last_block * fs->blocksize)) { + if (pb.is_dir) { + int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); + if ((nblock > (pb.last_block + 1)) || + ((inode->i_size & (fs->blocksize-1)) != 0)) + bad_size = 1; + else if (nblock < (pb.last_block + 1)) { + sb = (struct ext2fs_sb *) fs->super; + if (((pb.last_block + 1) - nblock) > + sb->s_prealloc_dir_blocks) + bad_size = 1; + } + } else { + size = inode->i_size + ((__u64) inode->i_size_high << 32); + if ((size < pb.last_block * fs->blocksize)) + bad_size = 1; + else if (size > ext2_max_sizes[fs->super->s_log_block_size]) + bad_size = 1; + } + if (bad_size) { pctx->num = (pb.last_block+1) * fs->blocksize; if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { inode->i_size = pctx->num; + if (!pb.is_dir) + inode->i_size_high = pctx->num >> 32; e2fsck_write_inode(ctx, ino, inode, "check_blocks"); } pctx->num = 0; } + if (!pb.is_dir && inode->i_size_high) + ctx->large_files++; if (pb.num_blocks != inode->i_blocks) { pctx->num = pb.num_blocks; if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { @@ -793,7 +849,7 @@ static char *describe_illegal_block(ext2_filsys fs, blk_t block) */ int process_block(ext2_filsys fs, blk_t *block_nr, - int blockcnt, + blkcnt_t blockcnt, blk_t ref_block, int ref_offset, void *priv_data) @@ -918,7 +974,7 @@ static void bad_block_indirect(e2fsck_t ctx, blk_t blk) int process_bad_block(ext2_filsys fs, blk_t *block_nr, - int blockcnt, + blkcnt_t blockcnt, blk_t ref_block, int ref_offset, void *priv_data) diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 52db68f..f52bc2e 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -667,6 +667,7 @@ static int process_bad_inode(e2fsck_t ctx, ino_t dir, ino_t ino) inode_modified++; } if (inode.i_dir_acl && + LINUX_S_ISDIR(inode.i_mode) && fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) { inode.i_dir_acl = 0; inode_modified++; @@ -778,4 +779,3 @@ static int update_dir_block(ext2_filsys fs, } return 0; } - diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 503e61e..f996b9b 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -400,6 +400,11 @@ static const struct e2fsck_problem problem_table[] = { /* Suppress messages prompt */ { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK }, + /* Filesystem contains large files, but has no such flag in sb */ + { PR_1_FEATURE_LARGE_FILES, + "@f contains large files, but lacks LARGE_FILE flag in @S.\n", + PROMPT_FIX, 0 }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 5788703..c4461a6 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -17,8 +17,9 @@ struct problem_context { struct ext2_inode *inode; struct ext2_dir_entry *dirent; blk_t blk, blk2; - int blkcount, group; - __u32 num; + blkcnt_t blkcount; + int group; + __u64 num; const char *str; }; @@ -229,6 +230,9 @@ struct problem_context { /* Suppress messages prompt */ #define PR_1_SUPPRESS_MESSAGES 0x010002D +/* Filesystem contains large files, but has no such flag in sb */ +#define PR_1_FEATURE_LARGE_FILES 0x01002E + /* * Pass 1b errors */ diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 5d36a75..855ab74 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -536,7 +536,7 @@ restart: */ s = (struct ext2fs_sb *) fs->super; if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) || - (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) { + (s->s_feature_incompat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) { com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, "(%s)", ctx->filesystem_name); goto get_newer; diff --git a/tests/ChangeLog b/tests/ChangeLog index 1024e61..39502fc 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +1998-03-23 Theodore Ts'o + + * f_messy_inode: Modify test to deal with changes to support + 64-bit size files. (/MAKEDEV had i_dir_acl, now + i_size_high, set.) + Sat Oct 25 18:38:56 1997 Theodore Ts'o * Add scripts to skip the e_brel_bma and e_irel_ima tests (since diff --git a/tests/f_messy_inode/expect.1 b/tests/f_messy_inode/expect.1 index ae5f52a..cc3efe5 100644 --- a/tests/f_messy_inode/expect.1 +++ b/tests/f_messy_inode/expect.1 @@ -12,15 +12,14 @@ Illegal block #7 (4294901760) in inode 14. CLEARED. Illegal block #8 (4294901760) in inode 14. CLEARED. Illegal block #9 (4294901760) in inode 14. CLEARED. Illegal block #10 (4294901760) in inode 14. CLEARED. +Inode 14, i_size is 18446462598732849291, should be 2048. Fix? yes + Inode 14, i_blocks is 18, should be 4. Fix? yes Pass 2: Checking directory structure i_file_acl for inode 14 (/MAKEDEV) is 4294901760, should be zero. Clear? yes -i_dir_acl for inode 14 (/MAKEDEV) is 4294901760, should be zero. -Clear? yes - Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information