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 <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):
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
}
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 @@
/* 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 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 @@
/* 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 @@
*/
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;