Whamcloud - gitweb
Many files:
authorTheodore Ts'o <tytso@mit.edu>
Tue, 24 Mar 1998 16:22:38 +0000 (16:22 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 24 Mar 1998 16:22:38 +0000 (16:22 +0000)
  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.)

e2fsck/ChangeLog
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/message.c
e2fsck/pass1.c
e2fsck/pass2.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/unix.c
tests/ChangeLog
tests/f_messy_inode/expect.1

index 0d0ef86..4d7b72f 100644 (file)
@@ -1,3 +1,49 @@
+1998-03-23  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * 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  <tytso@rsts-11.mit.edu>
 
        * pass3.c (fix_dotdot_proc): 
index 56437d5..41195fe 100644 (file)
@@ -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;
index b8ac30c..e1c5944 100644 (file)
@@ -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
index 82cb423..c839bbf 100644 (file)
@@ -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);
index e2a35f0..7ba9c63 100644 (file)
 #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)
index 52db68f..f52bc2e 100644 (file)
@@ -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;
 }
-       
index 503e61e..f996b9b 100644 (file)
@@ -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 */
index 5788703..c4461a6 100644 (file)
@@ -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
  */
index 5d36a75..855ab74 100644 (file)
@@ -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;
index 1024e61..39502fc 100644 (file)
@@ -1,3 +1,9 @@
+1998-03-23  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * 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  <tytso@rsts-11.mit.edu>
 
        * Add scripts to skip the e_brel_bma and e_irel_ima tests (since
index ae5f52a..cc3efe5 100644 (file)
@@ -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