diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index 5c1df966..15b5d48b 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,15 @@ +2002-05-21 Theodore Ts'o + + * pass1.c (process_block): If an inode has too many blocks or + is too big, then offer to truncate the inode. + (check_blocks): Don't bother checking the size to see if + it's too big, since that's just a symptom, not the disease + (which we're now appropriately checking in process_block). + + * problem.c, problem.h: Add new problem codes PR_1_INODE_TOOBIG, + PR_1_TOOBIG_DIR, PR_1_TOOBIG_REG, PR_1_TOOBIG_SYMLINK, and + add the latch code PR_LATCH_TOOBIG. + 2002-05-20 Theodore Ts'o * e2fsck.h, pass1.c (e2fsck_pass1_check_symlink), pass2.c diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 5828b13e..c8eee89e 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -76,9 +76,10 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, struct process_block_struct { ext2_ino_t ino; - int is_dir:1, clear:1, suppress:1, + int is_dir:1, is_reg:1, clear:1, suppress:1, fragmented:1, compressed:1; blk_t num_blocks; + blk_t max_blocks; e2_blkcnt_t last_block; int num_illegal_blocks; blk_t previous_block; @@ -410,7 +411,7 @@ void e2fsck_pass1(e2fsck_t ctx) pb.num_blocks = pb.last_block = 0; pb.num_illegal_blocks = 0; pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; - pb.fragmented = 0; + pb.is_reg = 0; pb.fragmented = 0; pb.inode = &inode; pb.pctx = &pctx; pb.ctx = ctx; @@ -1150,6 +1151,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, pb.compressed = 0; pb.previous_block = 0; pb.is_dir = LINUX_S_ISDIR(inode->i_mode); + pb.is_reg = LINUX_S_ISREG(inode->i_mode); + pb.max_blocks = 1 << (31 - fs->super->s_log_block_size); pb.inode = inode; pb.pctx = pctx; pb.ctx = ctx; @@ -1174,6 +1177,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; end_problem_latch(ctx, PR_LATCH_BLOCK); + end_problem_latch(ctx, PR_LATCH_TOOBIG); if (pctx->errcode) fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); @@ -1221,25 +1225,21 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, } if (pb.is_dir) { int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); - /* We don't let a directory become larger than 2GB */ - if (nblock > (pb.last_block + 1) || - (inode->i_size & ((fs->blocksize-1) | 0x80000000UL)) != 0) + if (nblock > (pb.last_block + 1)) bad_size = 1; else if (nblock < (pb.last_block + 1)) { if (((pb.last_block + 1) - nblock) > fs->super->s_prealloc_dir_blocks) bad_size = 2; } - } else if (!LINUX_S_ISREG(inode->i_mode)) { - if (inode->i_size_high) - bad_size = 5; } else { + if (!LINUX_S_ISREG(inode->i_mode) && inode->i_size_high) + bad_size = 5; size = inode->i_size | ((__u64) inode->i_size_high << 32); if ((size < pb.last_block * fs->blocksize)) bad_size = 3; else if (size > ext2_max_sizes[fs->super->s_log_block_size]) bad_size = 4; - /* FIXME: need to ensure pb.num_blocks < 2^32 */ } if (bad_size) { pctx->num = (pb.last_block+1) * fs->blocksize; @@ -1400,6 +1400,13 @@ static int process_block(ext2_filsys fs, } p->previous_block = blk; + if (p->is_dir && blockcnt > 2*1024*1024/fs->blocksize) + problem = PR_1_TOOBIG_DIR; + if (p->is_reg && p->num_blocks+1 >= p->max_blocks) + problem = PR_1_TOOBIG_REG; + if (!p->is_dir && !p->is_reg && blockcnt > 0) + problem = PR_1_TOOBIG_SYMLINK; + if (blk < fs->super->s_first_data_block || blk >= fs->super->s_blocks_count) problem = PR_1_ILLEGAL_BLOCK_NUM; diff --git a/e2fsck/problem.c b/e2fsck/problem.c index aaaa2708..e786fa2b 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -89,6 +89,7 @@ static const char *preen_msg[] = { N_("FILE DELETED"), /* 15 */ N_("SUPPRESSED"), /* 16 */ N_("UNLINKED"), /* 17 */ + "", /* 18 */ }; static const struct e2fsck_problem problem_table[] = { @@ -645,6 +646,25 @@ static const struct e2fsck_problem problem_table[] = { N_("@a @b %b is corrupt (invalid value). "), PROMPT_CLEAR, 0}, + /* Inode too big (latch question) */ + { PR_1_INODE_TOOBIG, + N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 }, + + /* Directory too big */ + { PR_1_TOOBIG_DIR, + N_("@b #%B (%b) causes @d to be too big. "), + PROMPT_CLEAR, PR_LATCH_TOOBIG }, + + /* Regular file too big */ + { PR_1_TOOBIG_REG, + N_("@b #%B (%b) causes file to be too big. "), + PROMPT_CLEAR, PR_LATCH_TOOBIG }, + + /* Symlink too big */ + { PR_1_TOOBIG_SYMLINK, + N_("@b #%B (%b) causes symlink to be too big. "), + PROMPT_CLEAR, PR_LATCH_TOOBIG }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ @@ -1255,6 +1275,7 @@ static struct latch_descr pr_latch_info[] = { { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 }, { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END }, { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 }, + { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 }, { -1, 0, 0 }, }; diff --git a/e2fsck/problem.h b/e2fsck/problem.h index f5eae27e..3c4b1620 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -36,6 +36,7 @@ struct problem_context { #define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */ #define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */ #define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */ +#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */ #define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1) @@ -372,6 +373,18 @@ struct problem_context { /* Bad extended attribute value */ #define PR_1_EA_BAD_VALUE 0x010042 +/* Inode too big (latch question) */ +#define PR_1_INODE_TOOBIG 0x010043 + +/* Directory too big */ +#define PR_1_TOOBIG_DIR 0x010044 + +/* Regular file too big */ +#define PR_1_TOOBIG_REG 0x010045 + +/* Symlink too big */ +#define PR_1_TOOBIG_SYMLINK 0x010046 + /* * Pass 1b errors */ diff --git a/tests/ChangeLog b/tests/ChangeLog index 27065923..018ef59e 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,5 +1,13 @@ 2002-05-21 Theodore Ts'o + * f_badsymlinks: Check for symlink too big error message. + + * f_lotsbad: Check for directory too big error message. + + * f_big_sparse: New test case which e2fsck's response to a large, + sparse file, and tests the code which adds the LARGE_FILE + feature to a filesystem. + * f_badsymlinks, f_filetype: Revert expected text since we're no longer checking for EXT2_INDEX_FL along with the other immutable flags. diff --git a/tests/f_badsymlinks/expect.1 b/tests/f_badsymlinks/expect.1 index df187e68..d8314b46 100644 --- a/tests/f_badsymlinks/expect.1 +++ b/tests/f_badsymlinks/expect.1 @@ -12,6 +12,11 @@ Inode 19, i_blocks is 2, should be 0. Fix? yes Special (device/socket/fifo/symlink) file (inode 20) has immutable or append-only flag set. Clear? yes +Inode 21 is too big. Truncate? yes + +Block #1 (22) causes symlink to be too big. CLEARED. +Inode 21, i_blocks is 4, should be 2. Fix? yes + Pass 2: Checking directory structure Symlink /empty_link (inode #17) is invalid. Clear? yes diff --git a/tests/f_big_sparse/expect.1 b/tests/f_big_sparse/expect.1 new file mode 100644 index 00000000..437ade74 --- /dev/null +++ b/tests/f_big_sparse/expect.1 @@ -0,0 +1,16 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 12, i_size is 61440, should be 4398050758656. Fix? yes + +Pass 2: Checking directory structure +Filesystem contains large files, but lacks LARGE_FILE flag in superblock. +Fix? yes + +Filesystem has feature flag(s) set, but is a revision 0 filesystem. Fix? yes + +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 12/64 files (0.0% non-contiguous), 27/100 blocks +Exit status is 1 diff --git a/tests/f_big_sparse/expect.2 b/tests/f_big_sparse/expect.2 new file mode 100644 index 00000000..ae45ec58 --- /dev/null +++ b/tests/f_big_sparse/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 12/64 files (0.0% non-contiguous), 27/100 blocks +Exit status is 0 diff --git a/tests/f_big_sparse/image.gz b/tests/f_big_sparse/image.gz new file mode 100644 index 00000000..027feebb Binary files /dev/null and b/tests/f_big_sparse/image.gz differ diff --git a/tests/f_big_sparse/name b/tests/f_big_sparse/name new file mode 100644 index 00000000..b9d9723f --- /dev/null +++ b/tests/f_big_sparse/name @@ -0,0 +1 @@ +big sparse file diff --git a/tests/f_lotsbad/expect.1 b/tests/f_lotsbad/expect.1 index 3ecca41c..d9e8a245 100644 --- a/tests/f_lotsbad/expect.1 +++ b/tests/f_lotsbad/expect.1 @@ -1,6 +1,13 @@ Filesystem did not have a UUID; generating one. Pass 1: Checking inodes, blocks, and sizes +Inode 13 is too big. Truncate? yes + +Block #16580876 (74) causes directory to be too big. CLEARED. +Inode 13, i_size is 15360, should be 12288. Fix? yes + +Inode 13, i_blocks is 32, should be 30. Fix? yes + Inode 12 has illegal block(s). Clear? yes Illegal block #12 (778398818) in inode 12. CLEARED. @@ -24,26 +31,31 @@ Entry 'termcap' in / (2) has deleted/unused inode 12. Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts +Inode 2 ref count is 5, should be 4. Fix? yes + Pass 5: Checking group summary information -Block bitmap differences: -(27--41) -(44--45) +Block bitmap differences: -(27--41) -(44--45) -(74--90) Fix? yes -Free blocks count wrong for group #0 (41, counted=58). +Free blocks count wrong for group #0 (9, counted=43). Fix? yes -Free blocks count wrong (41, counted=58). +Free blocks count wrong (9, counted=43). Fix? yes -Inode bitmap differences: -12 +Inode bitmap differences: -12 -14 Fix? yes -Free inodes count wrong for group #0 (20, counted=21). +Free inodes count wrong for group #0 (18, counted=20). Fix? yes -Free inodes count wrong (20, counted=21). +Directories count wrong for group #0 (4, counted=3). +Fix? yes + +Free inodes count wrong (18, counted=20). Fix? yes test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 11/32 files (0.0% non-contiguous), 42/100 blocks +test_filesys: 12/32 files (0.0% non-contiguous), 57/100 blocks Exit status is 1 diff --git a/tests/f_lotsbad/expect.2 b/tests/f_lotsbad/expect.2 index b83f4e6a..da1208f3 100644 --- a/tests/f_lotsbad/expect.2 +++ b/tests/f_lotsbad/expect.2 @@ -3,5 +3,5 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -test_filesys: 11/32 files (0.0% non-contiguous), 42/100 blocks +test_filesys: 12/32 files (0.0% non-contiguous), 57/100 blocks Exit status is 0 diff --git a/tests/f_lotsbad/image.gz b/tests/f_lotsbad/image.gz index 9386a9e9..8fd5d1ea 100644 Binary files a/tests/f_lotsbad/image.gz and b/tests/f_lotsbad/image.gz differ