From da307041e75bdf3b24c1eb43132a4f9d8a1b3844 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 21 May 2002 21:19:14 -0400 Subject: [PATCH] Check for inodes which are too big (either too many blocks, or would cause i_size to be too big), and offer to truncate the inode. Remove old bogus i_size checks. Add test case which tests e2fsck's handling of large sparse files. Older e2fsck with the old(er) bogus i_size checks didn't handle this correctly. --- e2fsck/ChangeLog | 12 ++++++++++++ e2fsck/pass1.c | 25 ++++++++++++++++--------- e2fsck/problem.c | 21 +++++++++++++++++++++ e2fsck/problem.h | 13 +++++++++++++ tests/ChangeLog | 8 ++++++++ tests/f_badsymlinks/expect.1 | 5 +++++ tests/f_big_sparse/expect.1 | 16 ++++++++++++++++ tests/f_big_sparse/expect.2 | 7 +++++++ tests/f_big_sparse/image.gz | Bin 0 -> 801 bytes tests/f_big_sparse/name | 1 + tests/f_lotsbad/expect.1 | 26 +++++++++++++++++++------- tests/f_lotsbad/expect.2 | 2 +- tests/f_lotsbad/image.gz | Bin 3552 -> 3694 bytes 13 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 tests/f_big_sparse/expect.1 create mode 100644 tests/f_big_sparse/expect.2 create mode 100644 tests/f_big_sparse/image.gz create mode 100644 tests/f_big_sparse/name 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 0000000000000000000000000000000000000000..027feebb111e4becd267726104cd8b15715adf0d GIT binary patch literal 801 zcmb2|=HR&h?3E1@b7pR0dMd-)JBI!ujuLDS-iwK}Ty|z*(O&7hu92@JKuTD;zJZgG zhqKX1_ss%Rv1x7c#Si&!+`Jq(K|te0|IORcn>@S&zRy#yoV<7M-P#Fn*1+aXHVVl zy~dliRDO6{;CGst;lSV1??1K&wN-!r-+k29o`HcOK>Kc9`I0;PUN8YUTd(Y@;{(zR zS3)em?f>w)WapXMbM_X|uh$$o^7eIkSXpdA7;5 z?e=vyZr!_ir3$FwL%qcR#sBu_h<*io!dQ3~$e1htfkeYEc_8^?x@mQ0%GB@wjo<%g zW?*pOmHf{R6b36_@DId9QXBwM!tkmdNI3lE2a+rPGomnoLJST2Gt5%`j6rJN?!CYQ cqzxqY{0FHX1q4FC;cN`!k}syy7#!Fb0B{K80RR91 literal 0 HcmV?d00001 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 9386a9e9be8b64aa0dcd8b572f15a52224d67b0a..8fd5d1ea7c61b90c0fe53154719ebf4aaf79e3ad 100644 GIT binary patch delta 3609 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 literal 3552 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