Whamcloud - gitweb
Check for inodes which are too big (either too many blocks, or
authorTheodore Ts'o <tytso@mit.edu>
Wed, 22 May 2002 01:19:14 +0000 (21:19 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 22 May 2002 01:19:14 +0000 (21:19 -0400)
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.

13 files changed:
e2fsck/ChangeLog
e2fsck/pass1.c
e2fsck/problem.c
e2fsck/problem.h
tests/ChangeLog
tests/f_badsymlinks/expect.1
tests/f_big_sparse/expect.1 [new file with mode: 0644]
tests/f_big_sparse/expect.2 [new file with mode: 0644]
tests/f_big_sparse/image.gz [new file with mode: 0644]
tests/f_big_sparse/name [new file with mode: 0644]
tests/f_lotsbad/expect.1
tests/f_lotsbad/expect.2
tests/f_lotsbad/image.gz

index 5c1df96..15b5d48 100644 (file)
@@ -1,3 +1,15 @@
+2002-05-21  Theodore Ts'o  <tytso@mit.edu>
+
+       * 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  <tytso@mit.edu>
 
        * e2fsck.h, pass1.c (e2fsck_pass1_check_symlink), pass2.c
index 5828b13..c8eee89 100644 (file)
@@ -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;
index aaaa270..e786fa2 100644 (file)
@@ -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 },
 };
 
index f5eae27..3c4b162 100644 (file)
@@ -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
  */
index 2706592..018ef59 100644 (file)
@@ -1,5 +1,13 @@
 2002-05-21  Theodore Ts'o  <tytso@mit.edu>
 
+       * 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.
index df187e6..d8314b4 100644 (file)
@@ -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 (file)
index 0000000..437ade7
--- /dev/null
@@ -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 (file)
index 0000000..ae45ec5
--- /dev/null
@@ -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 (file)
index 0000000..027feeb
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 (file)
index 0000000..b9d9723
--- /dev/null
@@ -0,0 +1 @@
+big sparse file
index 3ecca41..d9e8a24 100644 (file)
@@ -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 (9, counted=43).
 Fix? yes
 
-Free blocks count wrong for group #0 (41, counted=58).
+Free blocks count wrong (9, counted=43).
 Fix? yes
 
-Free blocks count wrong (41, counted=58).
+Inode bitmap differences:  -12 -14
 Fix? yes
 
-Inode bitmap differences:  -12
+Free inodes count wrong for group #0 (18, counted=20).
 Fix? yes
 
-Free inodes count wrong for group #0 (20, counted=21).
+Directories count wrong for group #0 (4, counted=3).
 Fix? yes
 
-Free inodes count wrong (20, counted=21).
+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
index b83f4e6..da1208f 100644 (file)
@@ -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
index 9386a9e..8fd5d1e 100644 (file)
Binary files a/tests/f_lotsbad/image.gz and b/tests/f_lotsbad/image.gz differ