[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sat, 02 Feb 2008 01:25:59 -0700
From: Andreas Dilger <adilger@....com>
To: "Theodore Ts'o" <tytso@....edu>, linux-ext4@...r.kernel.org
Subject: Re: [PATCH][0/28] e2fsprogs-extents.patch
Support for checking 32-bit extents format inodes and the INCOMPAT_EXTENTS
feature.
Clear the high 16 bits of extents and index entries, since the
extents patches did not do this explicitly. Some parts of this
code need fixing for checking > 32-bit block filesystems (when
INCOMPAT_64BIT support is added), marked "FIXME: 48-bit support".
Verify extent headers in blocks, logical ordering of extents,
logical ordering of indexes.
Add explicit checking of {d,t,}indirect and index blocks to detect
corruption instead of implicitly doing this by checking the referred
blocks and only block-at-a-time correctness. This avoids incorrectly
invoking the very lengthy duplicate blocks pass for bad indirect/index
blocks. We may want to tune the "threshold" for how many errors make
a "bad" indirect/index block.
Add ability to split or remove extents in order to allow extent
reallocation during the duplicate blocks pass.
Index: e2fsprogs-1.40.5/e2fsck/Makefile.in
===================================================================
--- e2fsprogs-1.40.5.orig/e2fsck/Makefile.in
+++ e2fsprogs-1.40.5/e2fsck/Makefile.in
@@ -256,6 +256,7 @@ super.o: $(srcdir)/super.c $(top_srcdir)
pass1.o: $(srcdir)/pass1.c $(srcdir)/e2fsck.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h \
$(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
$(top_srcdir)/lib/blkid/blkid.h $(top_builddir)/lib/blkid/blkid_types.h \
Index: e2fsprogs-1.40.5/e2fsck/e2fsck.h
===================================================================
--- e2fsprogs-1.40.5.orig/e2fsck/e2fsck.h
+++ e2fsprogs-1.40.5/e2fsck/e2fsck.h
@@ -328,6 +328,7 @@ struct e2fsck_struct {
__u32 large_files;
__u32 fs_ext_attr_inodes;
__u32 fs_ext_attr_blocks;
+ __u32 extent_files;
/* misc fields */
time_t now;
Index: e2fsprogs-1.40.5/e2fsck/pass1.c
===================================================================
--- e2fsprogs-1.40.5.orig/e2fsck/pass1.c
+++ e2fsprogs-1.40.5/e2fsck/pass1.c
@@ -46,6 +46,7 @@
#include "e2fsck.h"
#include <ext2fs/ext2_ext_attr.h>
+#include <ext2fs/ext3_extents.h>
#include "problem.h"
@@ -79,16 +80,19 @@ static void adjust_extattr_refcount(e2fs
struct process_block_struct {
ext2_ino_t ino;
unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
- fragmented:1, compressed:1, bbcheck:1;
+ fragmented:1, compressed:1, bbcheck:1, extent:1;
blk_t num_blocks;
blk_t max_blocks;
e2_blkcnt_t last_block;
int num_illegal_blocks;
+ int last_illegal_blocks;
blk_t previous_block;
struct ext2_inode *inode;
struct problem_context *pctx;
ext2fs_block_bitmap fs_meta_blocks;
e2fsck_t ctx;
+ struct ext3_extent_header *eh_prev;
+ void *block_buf;
};
struct process_inode_block {
@@ -137,7 +141,7 @@ int e2fsck_pass1_check_device_inode(ext2
* If the index flag is set, then this is a bogus
* device/fifo/socket
*/
- if (inode->i_flags & EXT2_INDEX_FL)
+ if (inode->i_flags & (EXT2_INDEX_FL | EXT4_EXTENTS_FL))
return 0;
/*
@@ -171,7 +175,7 @@ int e2fsck_pass1_check_symlink(ext2_fils
blk_t blocks;
if ((inode->i_size_high || inode->i_size == 0) ||
- (inode->i_flags & EXT2_INDEX_FL))
+ (inode->i_flags & (EXT2_INDEX_FL | EXT4_EXTENTS_FL)))
return 0;
blocks = ext2fs_inode_data_blocks(fs, inode);
@@ -484,7 +488,9 @@ void e2fsck_pass1(e2fsck_t ctx)
int imagic_fs;
int busted_fs_time = 0;
int inode_size;
-
+ struct ext3_extent_header *eh;
+ int extent_fs;
+
#ifdef RESOURCE_TRACK
init_resource_track(&rtrack, ctx->fs->io);
#endif
@@ -515,6 +521,7 @@ void e2fsck_pass1(e2fsck_t ctx)
#undef EXT2_BPP
imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
+ extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS);
/*
* Allocate bitmaps structures
@@ -891,8 +898,7 @@ void e2fsck_pass1(e2fsck_t ctx)
check_blocks(ctx, &pctx, block_buf);
continue;
}
- }
- else if (LINUX_S_ISFIFO (inode->i_mode) &&
+ } else if (LINUX_S_ISFIFO (inode->i_mode) &&
e2fsck_pass1_check_device_inode(fs, inode)) {
check_immutable(ctx, &pctx);
check_size(ctx, &pctx);
@@ -904,21 +910,75 @@ void e2fsck_pass1(e2fsck_t ctx)
ctx->fs_sockets_count++;
} else
mark_inode_bad(ctx, ino);
- if (inode->i_block[EXT2_IND_BLOCK])
- ctx->fs_ind_count++;
- if (inode->i_block[EXT2_DIND_BLOCK])
- ctx->fs_dind_count++;
- if (inode->i_block[EXT2_TIND_BLOCK])
- ctx->fs_tind_count++;
- if (inode->i_block[EXT2_IND_BLOCK] ||
- inode->i_block[EXT2_DIND_BLOCK] ||
- inode->i_block[EXT2_TIND_BLOCK] ||
- inode->i_file_acl) {
- inodes_to_process[process_inode_count].ino = ino;
- inodes_to_process[process_inode_count].inode = *inode;
- process_inode_count++;
- } else
- check_blocks(ctx, &pctx, block_buf);
+
+ eh = (struct ext3_extent_header *)inode->i_block;
+ if ((inode->i_flags & EXT4_EXTENTS_FL)) {
+ if ((LINUX_S_ISREG(inode->i_mode) ||
+ LINUX_S_ISDIR(inode->i_mode)) &&
+ ext2fs_extent_header_verify(eh, EXT2_N_BLOCKS *
+ sizeof(__u32)) == 0) {
+ if (!extent_fs &&
+ fix_problem(ctx,PR_1_EXTENT_FEATURE,&pctx)){
+ sb->s_feature_incompat |=
+ EXT3_FEATURE_INCOMPAT_EXTENTS;
+ ext2fs_mark_super_dirty(fs);
+ extent_fs = 1;
+ }
+ } else if (fix_problem(ctx, PR_1_SET_EXTENT_FL, &pctx)){
+ inode->i_flags &= ~EXT4_EXTENTS_FL;
+ e2fsck_write_inode(ctx, ino, inode, "pass1");
+ goto check_ind_inode;
+ }
+ } else if (extent_fs &&
+ (LINUX_S_ISREG(inode->i_mode) ||
+ LINUX_S_ISDIR(inode->i_mode)) &&
+ ext2fs_extent_header_verify(eh, EXT2_N_BLOCKS *
+ sizeof(__u32)) == 0 &&
+ fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx)) {
+ inode->i_flags |= EXT4_EXTENTS_FL;
+ e2fsck_write_inode(ctx, ino, inode, "pass1");
+ }
+ if (extent_fs && inode->i_flags & EXT4_EXTENTS_FL) {
+ ctx->extent_files++;
+ switch(eh->eh_depth) {
+ case 0:
+ break;
+ case 1:
+ ctx->fs_ind_count++;
+ break;
+ case 2:
+ ctx->fs_dind_count++;
+ break;
+ default:
+ ctx->fs_tind_count++;
+ break;
+ }
+ if (eh->eh_depth > 0) {
+ inodes_to_process[process_inode_count].ino = ino;
+ inodes_to_process[process_inode_count].inode = *inode;
+ process_inode_count++;
+ } else {
+ check_blocks(ctx, &pctx, block_buf);
+ }
+ } else {
+ check_ind_inode:
+ if (inode->i_block[EXT2_IND_BLOCK])
+ ctx->fs_ind_count++;
+ if (inode->i_block[EXT2_DIND_BLOCK])
+ ctx->fs_dind_count++;
+ if (inode->i_block[EXT2_TIND_BLOCK])
+ ctx->fs_tind_count++;
+ if (inode->i_block[EXT2_IND_BLOCK] ||
+ inode->i_block[EXT2_DIND_BLOCK] ||
+ inode->i_block[EXT2_TIND_BLOCK] ||
+ inode->i_file_acl) {
+ inodes_to_process[process_inode_count].ino = ino;
+ inodes_to_process[process_inode_count].inode = *inode;
+ process_inode_count++;
+ } else {
+ check_blocks(ctx, &pctx, block_buf);
+ }
+ }
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
return;
@@ -1426,10 +1486,23 @@ clear_extattr:
return 0;
}
+static int htree_blk_iter_cb(ext2_filsys fs EXT2FS_ATTR((unused)),
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+ blk_t ref_blk EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ blk_t *blk = priv_data;
+
+ *blk = *blocknr;
+
+ return BLOCK_ABORT;
+}
+
/* Returns 1 if bad htree, 0 if OK */
static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
- ext2_ino_t ino EXT2FS_ATTR((unused)),
- struct ext2_inode *inode,
+ ext2_ino_t ino, struct ext2_inode *inode,
char *block_buf)
{
struct ext2_dx_root_info *root;
@@ -1443,7 +1516,8 @@ static int handle_htree(e2fsck_t ctx, st
fix_problem(ctx, PR_1_HTREE_SET, pctx)))
return 1;
- blk = inode->i_block[0];
+ ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DATA_ONLY | BLOCK_FLAG_HOLE,
+ block_buf, htree_blk_iter_cb, &blk);
if (((blk == 0) ||
(blk < fs->super->s_first_data_block) ||
(blk >= fs->super->s_blocks_count)) &&
@@ -1480,6 +1554,135 @@ static int handle_htree(e2fsck_t ctx, st
return 0;
}
+/* sort 0 to the end of the list so we can exit early */
+static EXT2_QSORT_TYPE verify_ind_cmp(const void *a, const void *b)
+{
+ const __u32 blk_a = *(__u32 *)a - 1, blk_b = *(__u32 *)b - 1;
+
+ return blk_b > blk_a ? -1 : blk_a - blk_b;
+}
+
+/* Verify whether an indirect block is sane. If it has multiple references
+ * to the same block, or if it has a large number of bad or duplicate blocks
+ * chances are that it is corrupt and we should just clear it instead of
+ * trying to salvage it.
+ * NOTE: this needs to get a copy of the blocks, since it reorders them */
+static int e2fsck_ind_block_verify(struct process_block_struct *p,
+ void *block_buf, int buflen)
+{
+ __u32 blocks[EXT2_N_BLOCKS], *indir = block_buf;
+ int num_indir = buflen / sizeof(*indir);
+ int i, bad = 0;
+
+ if (num_indir == EXT2_N_BLOCKS) {
+ memcpy(blocks, block_buf, buflen);
+ indir = blocks;
+ }
+ qsort(indir, num_indir, sizeof(*indir), verify_ind_cmp);
+
+ for (i = 0; i < num_indir; i++) {
+ if (indir[i] == 0)
+ break;
+
+ /* bad block number, or duplicate block */
+ if (indir[i] < p->ctx->fs->super->s_first_data_block ||
+ indir[i] > p->ctx->fs->super->s_blocks_count ||
+ ext2fs_fast_test_block_bitmap(p->ctx->block_found_map,
+ indir[i]))
+ bad++;
+
+ /* shouldn't reference the same block twice within a block */
+ if (i > 0 && indir[i] == indir[i - 1])
+ bad++;
+ }
+
+ if ((num_indir <= EXT2_N_BLOCKS && bad > 4) || bad > 8)
+ return PR_1_INDIRECT_BAD;
+
+#if DEBUG_E2FSCK
+ /* For debugging, clobber buffer to ensure it doesn't appear sane */
+ memset(indir, 0xca, buflen);
+#endif
+ return 0;
+}
+
+static int e2fsck_ext_block_verify(struct process_block_struct *p,
+ void *block_buf, int buflen)
+{
+ struct ext3_extent_header *eh = block_buf, *eh_sav;
+ e2fsck_t ctx = p->ctx;
+ struct problem_context *pctx = p->pctx;
+ int i, problem = 0, high_bits_ok = 0;
+
+ if (ext2fs_extent_header_verify(eh, buflen))
+ return PR_1_EXTENT_IDX_BAD;
+
+ if (p->eh_prev && p->eh_prev->eh_depth != eh->eh_depth + 1)
+ return PR_1_EXTENT_IDX_BAD;
+
+ if (ctx->fs->super->s_blocks_count_hi) /* FIXME: 48-bit support ??? */
+ high_bits_ok = 1;
+
+ eh_sav = p->eh_prev;
+ p->eh_prev = eh;
+
+ if (eh->eh_depth == 0) {
+ struct ext3_extent *ex = EXT_FIRST_EXTENT(eh), *ex_prev = NULL;
+
+ for (i = 0; i < eh->eh_entries; i++, ex++) {
+ if (ex->ee_start_hi && !high_bits_ok &&
+ fix_problem(ctx, PR_1_EXTENT_HI, pctx)) {
+ ex->ee_start_hi = 0;
+ problem = PR_1_EXTENT_CHANGED;
+ }
+
+ if (ext2fs_extent_verify(ctx->fs, ex, ex_prev, NULL,0)){
+ p->num_illegal_blocks++;
+ pctx->blkcount = ex->ee_start;
+ pctx->num = ex->ee_len;
+ pctx->blk = ex->ee_block;
+ if (fix_problem(ctx, PR_1_EXTENT_BAD, pctx)) {
+ ext2fs_extent_remove(eh, ex);
+ i--; ex--; /* check next (moved) item */
+ problem = PR_1_EXTENT_CHANGED;
+ continue;
+ }
+ }
+
+ ex_prev = ex;
+ }
+ } else {
+ struct ext3_extent_idx *ix =EXT_FIRST_INDEX(eh), *ix_prev =NULL;
+
+ for (i = 0; i < eh->eh_entries; i++, ix++) {
+ if (ix->ei_leaf_hi && !high_bits_ok &&
+ fix_problem(ctx, PR_1_EXTENT_HI, pctx)) {
+ ix->ei_leaf_hi = ix->ei_unused = 0;
+ problem = PR_1_EXTENT_CHANGED;
+ }
+
+ if (ext2fs_extent_index_verify(ctx->fs, ix, ix_prev)) {
+ p->num_illegal_blocks++;
+ pctx->blkcount = ix->ei_leaf;;
+ pctx->num = i;
+ pctx->blk = ix->ei_block;
+ if (fix_problem(ctx, PR_1_EXTENT_IDX_BAD,pctx)){
+ ext2fs_extent_index_remove(eh, ix);
+ i--; ix--; /* check next (moved) item */
+ problem = PR_1_EXTENT_CHANGED;
+ continue;
+ }
+ }
+
+ ix_prev = ix;
+ }
+ }
+
+ p->eh_prev = eh_sav;
+
+ return problem;
+}
+
/*
* This subroutine is called on each inode to account for all of the
* blocks used by that inode.
@@ -1499,9 +1701,11 @@ static void check_blocks(e2fsck_t ctx, s
pb.num_blocks = 0;
pb.last_block = -1;
pb.num_illegal_blocks = 0;
+ pb.last_illegal_blocks = 0;
pb.suppress = 0; pb.clear = 0;
pb.fragmented = 0;
pb.compressed = 0;
+ pb.extent = !!(inode->i_flags & EXT4_EXTENTS_FL);
pb.previous_block = 0;
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
pb.is_reg = LINUX_S_ISREG(inode->i_mode);
@@ -1509,6 +1713,8 @@ static void check_blocks(e2fsck_t ctx, s
pb.inode = inode;
pb.pctx = pctx;
pb.ctx = ctx;
+ pb.eh_prev = NULL;
+ pb.block_buf = block_buf;
pctx->ino = ino;
pctx->errcode = 0;
@@ -1530,10 +1736,27 @@ static void check_blocks(e2fsck_t ctx, s
pb.num_blocks++;
}
- if (ext2fs_inode_has_valid_blocks(inode))
- pctx->errcode = ext2fs_block_iterate2(fs, ino,
- pb.is_dir ? BLOCK_FLAG_HOLE : 0,
- block_buf, process_block, &pb);
+ if (ext2fs_inode_has_valid_blocks(inode)) {
+ int problem = 0;
+
+ if (pb.extent)
+ problem = e2fsck_ext_block_verify(&pb, inode->i_block,
+ sizeof(inode->i_block));
+ else
+ problem = e2fsck_ind_block_verify(&pb, inode->i_block,
+ sizeof(inode->i_block));
+ if (problem == PR_1_EXTENT_CHANGED) {
+ dirty_inode++;
+ problem = 0;
+ }
+
+ if (problem && fix_problem(ctx, problem, pctx))
+ pb.clear = 1;
+ else
+ pctx->errcode = ext2fs_block_iterate2(fs, ino,
+ pb.is_dir ? BLOCK_FLAG_HOLE : 0,
+ block_buf, process_block, &pb);
+ }
end_problem_latch(ctx, PR_LATCH_BLOCK);
end_problem_latch(ctx, PR_LATCH_TOOBIG);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
@@ -1697,6 +1920,9 @@ static char *describe_illegal_block(ext2
}
#endif
+#define IND_BLKCNT(_b) ((_b) == BLOCK_COUNT_IND || (_b) == BLOCK_COUNT_DIND ||\
+ (_b) == BLOCK_COUNT_TIND)
+
/*
* This is a helper function for check_blocks().
*/
@@ -1775,7 +2001,8 @@ static int process_block(ext2_filsys fs,
* file be contiguous. (Which can never be true for really
* big files that are greater than a block group.)
*/
- if (!HOLE_BLKADDR(p->previous_block)) {
+ if (!HOLE_BLKADDR(p->previous_block) &&
+ !(p->extent && IND_BLKCNT(blockcnt))) {
if (p->previous_block+1 != blk)
p->fragmented = 1;
}
@@ -1792,9 +2019,34 @@ static int process_block(ext2_filsys fs,
blk >= fs->super->s_blocks_count)
problem = PR_1_ILLEGAL_BLOCK_NUM;
+ if (!problem && IND_BLKCNT(blockcnt) && p->ino != EXT2_RESIZE_INO) {
+ if (p->extent) {
+ if (ext2fs_read_ext_block(ctx->fs, blk, p->block_buf))
+ problem = PR_1_BLOCK_ITERATE;
+ else
+ problem = e2fsck_ext_block_verify(p,
+ p->block_buf,
+ fs->blocksize);
+ if (problem == PR_1_EXTENT_CHANGED) {
+ if (ext2fs_write_ext_block(ctx->fs, blk,
+ p->block_buf))
+ problem = PR_1_BLOCK_ITERATE;
+ }
+
+ } else {
+ if (ext2fs_read_ind_block(ctx->fs, blk, p->block_buf))
+ problem = PR_1_BLOCK_ITERATE;
+ else
+ problem = e2fsck_ind_block_verify(p,
+ p->block_buf,
+ fs->blocksize);
+ }
+ }
+
if (problem) {
p->num_illegal_blocks++;
- if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
+ if (!p->suppress &&
+ p->num_illegal_blocks - p->last_illegal_blocks > 12) {
if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
p->clear = 1;
return BLOCK_ABORT;
@@ -1804,9 +2056,12 @@ static int process_block(ext2_filsys fs,
set_latch_flags(PR_LATCH_BLOCK,
PRL_SUPPRESS, 0);
}
+ p->last_illegal_blocks = p->num_illegal_blocks;
}
pctx->blk = blk;
pctx->blkcount = blockcnt;
+ if (problem == PR_1_EXTENT_CHANGED)
+ goto mark_used;
if (fix_problem(ctx, problem, pctx)) {
blk = *block_nr = 0;
ret_code = BLOCK_CHANGED;
@@ -1815,6 +2070,7 @@ static int process_block(ext2_filsys fs,
return 0;
}
+mark_used:
if (p->ino == EXT2_RESIZE_INO) {
/*
* The resize inode has already be sanity checked
Index: e2fsprogs-1.40.5/e2fsck/pass2.c
===================================================================
--- e2fsprogs-1.40.5.orig/e2fsck/pass2.c
+++ e2fsprogs-1.40.5/e2fsck/pass2.c
@@ -285,7 +285,16 @@ void e2fsck_pass2(e2fsck_t ctx)
ext2fs_mark_super_dirty(fs);
}
}
-
+
+ if (!ctx->extent_files &&
+ (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)) {
+ if (fs->flags & EXT2_FLAG_RW) {
+ sb->s_feature_incompat &=
+ ~EXT3_FEATURE_INCOMPAT_EXTENTS;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
#ifdef RESOURCE_TRACK
if (ctx->options & E2F_OPT_TIME2) {
e2fsck_clear_progbar(ctx);
Index: e2fsprogs-1.40.5/e2fsck/problem.c
===================================================================
--- e2fsprogs-1.40.5.orig/e2fsck/problem.c
+++ e2fsprogs-1.40.5/e2fsck/problem.c
@@ -784,6 +784,46 @@ static struct e2fsck_problem problem_tab
N_("@i %i is a %It but it looks like it is really a directory.\n"),
PROMPT_FIX, 0 },
+ /* indirect block corrupt */
+ { PR_1_INDIRECT_BAD,
+ N_("@i %i has corrupt indirect block\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* inode has extents, superblock missing INCOMPAT_EXTENTS feature */
+ { PR_1_EXTENT_FEATURE,
+ N_("@i %i is in extent format, but @S is missing EXTENTS feature\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* inode has EXTENTS_FL set, but is not an extent inode */
+ { PR_1_SET_EXTENT_FL,
+ N_("@i %i has EXTENT_FL set, but is not in extents format\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* inode missing EXTENTS_FL, but is an extent inode */
+ { PR_1_UNSET_EXTENT_FL,
+ N_("@i %i missing EXTENT_FL, but is in extents format\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* extent index corrupt */
+ { PR_1_EXTENT_BAD,
+ N_("@i %i has corrupt extent at @b %b (logical %B) length %N\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* extent index corrupt */
+ { PR_1_EXTENT_IDX_BAD,
+ N_("@i %i has corrupt extent index at @b %b (logical %B) entry %N\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* extent has high 16 bits set */
+ { PR_1_EXTENT_HI,
+ N_("High 16 bits of extent/index @b set\n"),
+ PROMPT_CLEAR, PR_LATCH_EXTENT_HI|PR_PREEN_OK|PR_NO_OK|PR_PREEN_NOMSG},
+
+ /* extent has high 16 bits set header */
+ { PR_1_EXTENT_HI_LATCH,
+ N_("@i %i has high 16 bits of extent/index @b set\n"),
+ PROMPT_CLEAR, PR_PREEN_OK | PR_NO_OK | PR_PREEN_NOMSG },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
@@ -1518,6 +1558,7 @@ static struct latch_descr pr_latch_info[
{ PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
{ PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
{ PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
+ { PR_LATCH_EXTENT_HI, PR_1_EXTENT_HI_LATCH, 0 },
{ -1, 0, 0 },
};
Index: e2fsprogs-1.40.5/e2fsck/problem.h
===================================================================
--- e2fsprogs-1.40.5.orig/e2fsck/problem.h
+++ e2fsprogs-1.40.5/e2fsck/problem.h
@@ -38,6 +38,7 @@ struct problem_context {
#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_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
+#define PR_LATCH_EXTENT_HI 0x00A0 /* Latch for extent high bits set */
#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
@@ -455,6 +456,33 @@ struct problem_context {
/* inode appears to be a directory */
#define PR_1_TREAT_AS_DIRECTORY 0x010055
+/* indirect block corrupt */
+#define PR_1_INDIRECT_BAD 0x010059
+
+/* wrong EXT3_FEATURE_INCOMPAT_EXTENTS flag */
+#define PR_1_EXTENT_FEATURE 0x010060
+
+/* EXT4_EXTENT_FL flag set on non-extent file */
+#define PR_1_SET_EXTENT_FL 0x010061
+
+/* EXT4_EXTENT_FL flag not set extent file */
+#define PR_1_UNSET_EXTENT_FL 0x010062
+
+/* extent index corrupt */
+#define PR_1_EXTENT_BAD 0x010063
+
+/* extent index corrupt */
+#define PR_1_EXTENT_IDX_BAD 0x010064
+
+/* extent/index has high 16 bits set - header */
+#define PR_1_EXTENT_HI 0x010065
+
+/* extent/index has high 16 bits set */
+#define PR_1_EXTENT_HI_LATCH 0x010066
+
+/* extent/index was modified & repaired - not really a problem */
+#define PR_1_EXTENT_CHANGED 0x010067
+
/*
* Pass 1b errors
*/
Index: e2fsprogs-1.40.5/lib/ext2fs/Makefile.in
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/Makefile.in
+++ e2fsprogs-1.40.5/lib/ext2fs/Makefile.in
@@ -35,6 +35,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_O
dir_iterate.o \
expanddir.o \
ext_attr.o \
+ extents.o \
finddev.o \
flushb.o \
freefs.o \
@@ -90,6 +91,7 @@ SRCS= ext2_err.c \
$(srcdir)/dupfs.c \
$(srcdir)/expanddir.c \
$(srcdir)/ext_attr.c \
+ $(srcdir)/extents.c \
$(srcdir)/fileio.c \
$(srcdir)/finddev.c \
$(srcdir)/flushb.c \
@@ -127,6 +129,7 @@ SRCS= ext2_err.c \
$(srcdir)/tst_bitops.c \
$(srcdir)/tst_byteswap.c \
$(srcdir)/tst_getsize.c \
+ $(srcdir)/tst_types.c \
$(srcdir)/tst_iscan.c \
$(srcdir)/unix_io.c \
$(srcdir)/unlink.c \
@@ -394,6 +397,10 @@ ext_attr.o: $(srcdir)/ext_attr.c $(srcdi
$(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
$(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+extents.o: $(srcdir)/extents.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext3_extents.h \
+ $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
fileio.o: $(srcdir)/fileio.c $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
Index: e2fsprogs-1.40.5/lib/ext2fs/block.c
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/block.c
+++ e2fsprogs-1.40.5/lib/ext2fs/block.c
@@ -17,24 +17,17 @@
#include "ext2_fs.h"
#include "ext2fs.h"
+#include "block.h"
-struct block_context {
- ext2_filsys fs;
- int (*func)(ext2_filsys fs,
- blk_t *blocknr,
- e2_blkcnt_t bcount,
- blk_t ref_blk,
- int ref_offset,
- void *priv_data);
- e2_blkcnt_t bcount;
- int bsize;
- int flags;
- errcode_t errcode;
- char *ind_buf;
- char *dind_buf;
- char *tind_buf;
- void *priv_data;
-};
+#ifdef EXT_DEBUG
+void ext_show_inode(struct ext2_inode *inode, ext2_ino_t ino)
+{
+ printf("inode: %u blocks: %u\n",
+ ino, inode->i_blocks);
+}
+#else
+#define ext_show_inode(inode, ino) do { } while (0)
+#endif
static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
int ref_offset, struct block_context *ctx)
@@ -276,7 +269,6 @@ errcode_t ext2fs_block_iterate2(ext2_fil
void *priv_data)
{
int i;
- int got_inode = 0;
int ret = 0;
blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
struct ext2_inode inode;
@@ -286,19 +278,20 @@ errcode_t ext2fs_block_iterate2(ext2_fil
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+ ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+ if (ctx.errcode)
+ return ctx.errcode;
+
/*
* Check to see if we need to limit large files
*/
if (flags & BLOCK_FLAG_NO_LARGE) {
- ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
- if (ctx.errcode)
- return ctx.errcode;
- got_inode = 1;
if (!LINUX_S_ISDIR(inode.i_mode) &&
(inode.i_size_high != 0))
return EXT2_ET_FILE_TOO_BIG;
}
+ /* The in-memory inode may have been changed by e2fsck */
retval = ext2fs_get_blocks(fs, ino, blocks);
if (retval)
return retval;
@@ -325,10 +318,6 @@ errcode_t ext2fs_block_iterate2(ext2_fil
*/
if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
!(flags & BLOCK_FLAG_DATA_ONLY)) {
- ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
- if (ctx.errcode)
- goto abort_exit;
- got_inode = 1;
if (inode.osd1.hurd1.h_i_translator) {
ret |= (*ctx.func)(fs,
&inode.osd1.hurd1.h_i_translator,
@@ -338,7 +327,16 @@ errcode_t ext2fs_block_iterate2(ext2_fil
goto abort_exit;
}
}
-
+
+ /* Iterate over normal data blocks with extents.
+ * We can't do any fixing here because this gets called by other
+ * callers than e2fsck_pass1->check_blocks(). */
+ if (inode.i_flags & EXT4_EXTENTS_FL) {
+ ext_show_inode(&inode, ino);
+ ret |= block_iterate_extents(blocks, sizeof(blocks), 0, 0,&ctx);
+ goto abort_exit;
+ }
+
/*
* Iterate over normal data blocks
*/
@@ -373,11 +371,6 @@ errcode_t ext2fs_block_iterate2(ext2_fil
abort_exit:
if (ret & BLOCK_CHANGED) {
- if (!got_inode) {
- retval = ext2fs_read_inode(fs, ino, &inode);
- if (retval)
- return retval;
- }
for (i=0; i < EXT2_N_BLOCKS; i++)
inode.i_block[i] = blocks[i];
retval = ext2fs_write_inode(fs, ino, &inode);
Index: e2fsprogs-1.40.5/lib/ext2fs/block.h
===================================================================
--- /dev/null
+++ e2fsprogs-1.40.5/lib/ext2fs/block.h
@@ -0,0 +1,33 @@
+/*
+ * block.h --- header for block iteration in block.c, extent.c
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+struct block_context {
+ ext2_filsys fs;
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t bcount,
+ blk_t ref_blk,
+ int ref_offset,
+ void *priv_data);
+ e2_blkcnt_t bcount;
+ int bsize;
+ int flags;
+ errcode_t errcode;
+ char *ind_buf;
+ char *dind_buf;
+ char *tind_buf;
+ void *priv_data;
+};
+
+/* libext2fs nternal function, in extent.c */
+extern int block_iterate_extents(void *eh_buf, unsigned bufsize,blk_t ref_block,
+ int ref_offset EXT2FS_ATTR((unused)),
+ struct block_context *ctx);
Index: e2fsprogs-1.40.5/lib/ext2fs/bmap.c
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/bmap.c
+++ e2fsprogs-1.40.5/lib/ext2fs/bmap.c
@@ -17,6 +17,7 @@
#include "ext2_fs.h"
#include "ext2fs.h"
+#include "ext3_extents.h"
#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
#define _BMAP_INLINE_ __inline__
@@ -31,6 +32,65 @@ extern errcode_t ext2fs_bmap(ext2_filsys
#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
+/* see also block_iterate_extents() */
+static errcode_t block_bmap_extents(void *eh_buf, unsigned bufsize,
+ ext2_filsys fs, blk_t block,blk_t *phys_blk)
+{
+ struct ext3_extent_header *eh = eh_buf;
+ struct ext3_extent *ex;
+ errcode_t ret = 0;
+ int i;
+
+ ret = ext2fs_extent_header_verify(eh, bufsize);
+ if (ret)
+ return ret;
+
+ if (eh->eh_depth == 0) {
+ ex = EXT_FIRST_EXTENT(eh);
+ for (i = 0; i < eh->eh_entries; i++, ex++) {
+ if (block < ex->ee_block)
+ continue;
+
+ if (block < ex->ee_block + ex->ee_len)
+ /* FIXME: 48-bit support */
+ *phys_blk = ex->ee_start + block - ex->ee_block;
+
+ /* only the first extent > block could hold the block
+ * otherwise the extents would overlap */
+ break;
+ }
+ } else {
+ struct ext3_extent_idx *ix;
+ char *block_buf;
+
+ ret = ext2fs_get_mem(fs->blocksize, &block_buf);
+ if (ret)
+ return ret;
+
+ ix = EXT_FIRST_INDEX(eh);
+ for (i = 0; i < eh->eh_entries; i++, ix++) {
+ if (block < ix->ei_block)
+ continue;
+
+ ret = io_channel_read_blk(fs->io, ix->ei_leaf, 1,
+ block_buf);
+ if (ret)
+ goto free_buf;
+
+ ret = block_bmap_extents(block_buf, fs->blocksize,
+ fs, block, phys_blk);
+
+ /* only the first extent > block could hold the block
+ * otherwise the extents would overlap */
+ break;
+ }
+
+ free_buf:
+ ext2fs_free_mem(&block_buf);
+ }
+ return ret;
+}
+
static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
blk_t ind, char *block_buf,
int *blocks_alloc,
@@ -149,6 +209,16 @@ errcode_t ext2fs_bmap(ext2_filsys fs, ex
return retval;
inode = &inode_buf;
}
+
+ if (inode->i_flags & EXT4_EXTENTS_FL) {
+ if (bmap_flags) /* unsupported as yet */
+ return EXT2_ET_BLOCK_ALLOC_FAIL;
+ retval = block_bmap_extents(inode->i_block,
+ sizeof(inode->i_block),
+ fs, block, phys_blk);
+ goto done;
+ }
+
addr_per_block = (blk_t) fs->blocksize >> 2;
if (!block_buf) {
Index: e2fsprogs-1.40.5/lib/ext2fs/ext2_err.et.in
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/ext2_err.et.in
+++ e2fsprogs-1.40.5/lib/ext2fs/ext2_err.et.in
@@ -326,5 +326,17 @@ ec EXT2_ET_TDB_ERR_NOEXIST,
ec EXT2_ET_TDB_ERR_RDONLY,
"TDB: Write not permitted"
+ec EXT2_ET_EXTENT_HEADER_BAD,
+ "Corrupt extent header"
+
+ec EXT2_ET_EXTENT_INDEX_BAD,
+ "Corrupt extent index"
+
+ec EXT2_ET_EXTENT_LEAF_BAD,
+ "Corrupt extent"
+
+ec EXT2_ET_EXTENT_NO_SPACE,
+ "No free space in extent map"
+
end
Index: e2fsprogs-1.40.5/lib/ext2fs/ext2fs.h
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/ext2fs.h
+++ e2fsprogs-1.40.5/lib/ext2fs/ext2fs.h
@@ -436,12 +436,14 @@ typedef struct ext2_icount *ext2_icount_
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
EXT2_FEATURE_INCOMPAT_META_BG|\
EXT3_FEATURE_INCOMPAT_RECOVER|\
+ EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG)
#else
#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
EXT2_FEATURE_INCOMPAT_META_BG|\
EXT3_FEATURE_INCOMPAT_RECOVER|\
+ EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG)
#endif
#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
@@ -722,6 +724,21 @@ extern errcode_t ext2fs_adjust_ea_refcou
char *block_buf,
int adjust, __u32 *newcount);
+/* extent.c */
+errcode_t ext2fs_extent_header_verify(struct ext3_extent_header *eh, int size);
+errcode_t ext2fs_extent_verify(ext2_filsys fs, struct ext3_extent *ex,
+ struct ext3_extent *ex_prev,
+ struct ext3_extent_idx *ix, int ix_len);
+errcode_t ext2fs_extent_index_verify(ext2_filsys fs,
+ struct ext3_extent_idx *ix,
+ struct ext3_extent_idx *ix_prev);
+errcode_t ext2fs_extent_remove(struct ext3_extent_header *eh,
+ struct ext3_extent *ex);
+errcode_t ext2fs_extent_split(ext2_filsys fs, struct ext3_extent_header **eh,
+ struct ext3_extent **ex, int count, int *flag);
+errcode_t ext2fs_extent_index_remove(struct ext3_extent_header *eh,
+ struct ext3_extent_idx *ix);
+
/* fileio.c */
extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
@@ -810,6 +827,8 @@ extern errcode_t ext2fs_image_bitmap_rea
/* ind_block.c */
errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf);
errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf);
+errcode_t ext2fs_read_ext_block(ext2_filsys fs, blk_t blk, void *buf);
+errcode_t ext2fs_write_ext_block(ext2_filsys fs, blk_t blk, void *buf);
/* initialize.c */
extern errcode_t ext2fs_initialize(const char *name, int flags,
@@ -984,6 +1003,9 @@ extern void ext2fs_swap_inode_full(ext2_
int bufsize);
extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
struct ext2_inode *f, int hostorder);
+extern void ext2fs_swap_extent_header(struct ext3_extent_header *eh);
+extern void ext2fs_swap_extent_index(struct ext3_extent_idx *ix);
+extern void ext2fs_swap_extent(struct ext3_extent *ex);
/* valid_blk.c */
extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
Index: e2fsprogs-1.40.5/lib/ext2fs/extents.c
===================================================================
--- /dev/null
+++ e2fsprogs-1.40.5/lib/ext2fs/extents.c
@@ -0,0 +1,475 @@
+/*
+ * extent.c --- iterate over all blocks in an extent-mapped inode
+ *
+ * Copyright (C) 2005 Alex Tomas <alex@...sterfs.com>
+ * Copyright (C) 2006 Andreas Dilger <adilger@...sterfs.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "block.h"
+
+#ifdef EXT_DEBUG
+void ext_show_header(struct ext3_extent_header *eh)
+{
+ printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n",
+ eh->eh_magic, eh->eh_entries, eh->eh_max, eh->eh_depth,
+ eh->eh_generation);
+}
+
+void ext_show_index(struct ext3_extent_idx *ix)
+{
+ printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n",
+ ix->ei_block, ix->ei_leaf, ix->ei_leaf_hi, ix->ei_unused);
+}
+
+void ext_show_extent(struct ext3_extent *ex)
+{
+ printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n",
+ ex->ee_block, ex->ee_block + ex->ee_len - 1,
+ ex->ee_len, ex->ee_start, ex->ee_start_hi);
+}
+
+#define ext_printf(fmt, args...) printf(fmt, ## args)
+#else
+#define ext_show_header(eh) do { } while (0)
+#define ext_show_index(ix) do { } while (0)
+#define ext_show_extent(ex) do { } while (0)
+#define ext_printf(fmt, args...) do { } while (0)
+#endif
+
+errcode_t ext2fs_extent_header_verify(struct ext3_extent_header *eh, int size)
+{
+ int eh_max, entry_size;
+
+ ext_show_header(eh);
+ if (eh->eh_magic != EXT3_EXT_MAGIC)
+ return EXT2_ET_EXTENT_HEADER_BAD;
+ if (eh->eh_entries > eh->eh_max)
+ return EXT2_ET_EXTENT_HEADER_BAD;
+ if (eh->eh_depth == 0)
+ entry_size = sizeof(struct ext3_extent);
+ else
+ entry_size = sizeof(struct ext3_extent_idx);
+
+ eh_max = (size - sizeof(*eh)) / entry_size;
+ /* Allow two extent-sized items at the end of the block, for
+ * ext4_extent_tail with checksum in the future. */
+ if (eh->eh_max > eh_max || eh->eh_max < eh_max - 2)
+ return EXT2_ET_EXTENT_HEADER_BAD;
+
+ return 0;
+}
+
+/* Verify that a single extent @ex is valid. If @ex_prev is passed in,
+ * then this was the previous logical extent in this block and we can
+ * do additional sanity checking (though in case of error we don't know
+ * which of the two extents is bad). Similarly, if @ix is passed in
+ * we can check that this extent is logically part of the index that
+ * refers to it (though again we can't know which of the two is bad). */
+errcode_t ext2fs_extent_verify(ext2_filsys fs, struct ext3_extent *ex,
+ struct ext3_extent *ex_prev,
+ struct ext3_extent_idx *ix, int ix_len)
+{
+ ext_show_extent(ex);
+ /* FIXME: 48-bit support */
+ if (ex->ee_start > fs->super->s_blocks_count)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ if (ex->ee_len == 0)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ if (ex->ee_len >= fs->super->s_blocks_per_group)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ if (ex_prev) {
+ /* We can't have a zero logical block except for first index */
+ if (ex->ee_block == 0)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ /* FIXME: 48-bit support */
+ /* extents must be in logical offset order */
+ if (ex->ee_block < ex_prev->ee_block + ex_prev->ee_len)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ /* extents must not overlap physical blocks */
+ if ((ex->ee_start < ex_prev->ee_start + ex_prev->ee_len) &&
+ (ex->ee_start + ex->ee_len > ex_prev->ee_start))
+ return EXT2_ET_EXTENT_LEAF_BAD;
+ }
+
+ if (ix) {
+ /* FIXME: 48-bit support */
+ if (ex->ee_block < ix->ei_block)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ if (ix_len && ex->ee_block + ex->ee_len > ix->ei_block + ix_len)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+ }
+
+ return 0;
+}
+
+errcode_t ext2fs_extent_index_verify(ext2_filsys fs, struct ext3_extent_idx *ix,
+ struct ext3_extent_idx *ix_prev)
+{
+ ext_show_index(ix);
+ /* FIXME: 48-bit support */
+ if (ix->ei_leaf > fs->super->s_blocks_count)
+ return EXT2_ET_EXTENT_INDEX_BAD;
+
+ if (ix_prev == NULL)
+ return 0;
+
+ /* We can't have a zero logical block except for first index */
+ if (ix->ei_block == 0)
+ return EXT2_ET_EXTENT_INDEX_BAD;
+
+ if (ix->ei_block <= ix_prev->ei_block)
+ return EXT2_ET_EXTENT_INDEX_BAD;
+
+ return 0;
+}
+
+errcode_t ext2fs_extent_remove(struct ext3_extent_header *eh,
+ struct ext3_extent *ex)
+{
+ int offs = ex - EXT_FIRST_EXTENT(eh);
+
+ if (offs < 0 || offs > eh->eh_entries)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ ext_printf("remove extent: offset %u\n", offs);
+
+ memmove(ex, ex + 1, (eh->eh_entries - offs - 1) * sizeof(*ex));
+ --eh->eh_entries;
+
+ return 0;
+}
+
+static errcode_t ext2fs_extent_split_internal(struct ext3_extent_header *eh,
+ struct ext3_extent *ex, int offs)
+{
+ int entry = ex - EXT_FIRST_EXTENT(eh);
+ struct ext3_extent *ex_new = ex + 1;
+
+ ext_printf("split: ee_len: %u ee_block: %u ee_start: %u offset: %u\n",
+ ex->ee_len, ex->ee_block, ex->ee_start, offs);
+ memmove(ex_new, ex, (eh->eh_entries - entry) * sizeof(*ex));
+ ++eh->eh_entries;
+
+ ex->ee_len = offs;
+ /* FIXME: 48-bit support */
+ ex_new->ee_len -= offs;
+ ex_new->ee_block += offs;
+ ex_new->ee_start += offs;
+
+ return 0;
+}
+
+errcode_t ext2fs_extent_split(ext2_filsys fs,
+ struct ext3_extent_header **eh_orig,
+ struct ext3_extent **ex_orig, int offs, int *flag)
+{
+ struct ext3_extent_header *eh_parent = *eh_orig;
+ int retval, entry = *ex_orig - EXT_FIRST_EXTENT(eh_parent);
+ blk_t new_block;
+ char *buf;
+ struct ext3_extent_idx *ei = EXT_FIRST_INDEX(eh_parent);
+
+ if (entry < 0 || entry > (*eh_orig)->eh_entries)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ if (offs > (*ex_orig)->ee_len)
+ return EXT2_ET_EXTENT_LEAF_BAD;
+
+ if (eh_parent->eh_entries >= eh_parent->eh_max) {
+ ext_printf("split: eh_entries: %u eh_max: %u\n",
+ eh_parent->eh_entries, eh_parent->eh_max);
+ if (eh_parent->eh_max == 4) {
+ struct ext3_extent_header *eh_child;
+ struct ext3_extent *ex_child;
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+
+ if (retval)
+ return EXT2_ET_EXTENT_NO_SPACE;
+
+ memset(buf, 0, fs->blocksize);
+ memcpy(buf, eh_parent, sizeof(*eh_parent) +
+ eh_parent->eh_entries * sizeof(*ex_child));
+ eh_child = (struct ext3_extent_header *)buf;
+
+ eh_child->eh_max = (fs->blocksize -
+ sizeof(struct ext3_extent_header)) /
+ sizeof(struct ext3_extent);
+ retval = ext2fs_new_block(fs, (*ex_orig)->ee_block, 0,
+ &new_block);
+ if (retval)
+ return EXT2_ET_EXTENT_NO_SPACE;
+
+ retval = io_channel_write_blk(fs->io, new_block, 1,buf);
+ if (retval)
+ return EXT2_ET_EXTENT_NO_SPACE;
+
+ eh_parent->eh_entries = 1;
+ eh_parent->eh_depth = 1;
+
+ ex_child = EXT_FIRST_EXTENT(eh_child);
+ ei->ei_block = ex_child->ee_block;
+ /* FIXME: 48-bit support*/
+ ei->ei_leaf = new_block;
+
+ *eh_orig = eh_child;
+ *ex_orig = EXT_FIRST_EXTENT(eh_child) + entry;
+
+ *flag = BLOCK_CHANGED;
+ } else {
+ return EXT2_ET_EXTENT_NO_SPACE;
+ }
+ }
+
+ return ext2fs_extent_split_internal(*eh_orig, *ex_orig, offs);
+}
+
+errcode_t ext2fs_extent_index_remove(struct ext3_extent_header *eh,
+ struct ext3_extent_idx *ix)
+{
+ struct ext3_extent_idx *first = EXT_FIRST_INDEX(eh);
+ int offs = ix - first;
+
+ ext_printf("remove index: offset %u\n", offs);
+
+ memmove(ix, ix + 1, (eh->eh_entries - offs - 1) * sizeof(*ix));
+ --eh->eh_entries;
+
+ return 0;
+}
+
+/* Internal function for ext2fs_block_iterate2() to recursively walk the
+ * extent tree, with a callback function for each block. We also call the
+ * callback function on index blocks unless BLOCK_FLAG_DATA_ONLY is given.
+ * We traverse the tree in-order (internal nodes before their children)
+ * unless BLOCK_FLAG_DEPTH_FIRST is given.
+ *
+ * See also block_bmap_extents(). */
+int block_iterate_extents(void *eh_buf, unsigned bufsize, blk_t ref_block,
+ int ref_offset EXT2FS_ATTR((unused)),
+ struct block_context *ctx)
+{
+ struct ext3_extent_header *orig_eh, *eh;
+ struct ext3_extent *ex, *ex_prev = NULL;
+ int ret = 0;
+ int item, offs, flags, split_flag = 0;
+ blk_t block_address;
+
+ orig_eh = eh = eh_buf;
+
+ if (ext2fs_extent_header_verify(eh, bufsize))
+ return BLOCK_ERROR;
+
+ if (eh->eh_depth == 0) {
+ ex = EXT_FIRST_EXTENT(eh);
+ for (item = 0; item < eh->eh_entries; item++, ex++) {
+ ext_show_extent(ex);
+ for (offs = 0; offs < ex->ee_len; offs++) {
+ block_address = ex->ee_start + offs;
+ flags = (*ctx->func)(ctx->fs, &block_address,
+ (ex->ee_block + offs),
+ ref_block, item,
+ ctx->priv_data);
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags &(BLOCK_ABORT|BLOCK_ERROR);
+ return ret;
+ }
+ if (!(flags & BLOCK_CHANGED))
+ continue;
+
+ ext_printf("extent leaf changed: "
+ "block was %u+%u = %u, now %u\n",
+ ex->ee_start, offs,
+ ex->ee_start + offs, block_address);
+
+ /* FIXME: 48-bit support */
+ if (ex_prev &&
+ block_address ==
+ ex_prev->ee_start + ex_prev->ee_len &&
+ ex->ee_block + offs ==
+ ex_prev->ee_block + ex_prev->ee_len) {
+ /* can merge block with prev extent */
+ ex_prev->ee_len++;
+ ex->ee_len--;
+ ret |= BLOCK_CHANGED;
+
+ if (ex->ee_len == 0) {
+ /* no blocks left in this one */
+ ext2fs_extent_remove(eh, ex);
+ item--; ex--;
+ break;
+ } else {
+ /* FIXME: 48-bit support */
+ ex->ee_start++;
+ ex->ee_block++;
+ offs--;
+ }
+
+ } else if (offs > 0 && /* implies ee_len > 1 */
+ (ctx->errcode =
+ ext2fs_extent_split(ctx->fs, &eh,
+ &ex, offs,
+ &split_flag)
+ /* advance ex past newly split item,
+ * comparison is bogus to make sure
+ * increment doesn't change logic */
+ || (offs > 0 && ex++ == NULL))) {
+ /* split before new block failed */
+ ret |= BLOCK_ABORT | BLOCK_ERROR;
+ return ret;
+
+ } else if (ex->ee_len > 1 &&
+ (ctx->errcode =
+ ext2fs_extent_split(ctx->fs, &eh,
+ &ex, 1,
+ &split_flag))) {
+ /* split after new block failed */
+ ret |= BLOCK_ABORT | BLOCK_ERROR;
+ return ret;
+
+ } else {
+ if (ex->ee_len != 1) {
+ /* this is an internal error */
+ ctx->errcode =
+ EXT2_ET_EXTENT_INDEX_BAD;
+ ret |= BLOCK_ABORT |BLOCK_ERROR;
+ return ret;
+ }
+ /* FIXME: 48-bit support */
+ ex->ee_start = block_address;
+ ret |= BLOCK_CHANGED;
+ }
+ }
+ ex_prev = ex;
+ }
+ /* Multi level split at depth == 0.
+ * ex has been changed to point to newly allocated block
+ * buffer. And after returning in this scenario, only inode is
+ * updated with changed i_block. Hence explicitly write to the
+ * block is required. */
+ if (split_flag == BLOCK_CHANGED) {
+ struct ext3_extent_idx *ix = EXT_FIRST_INDEX(orig_eh);
+ ctx->errcode = ext2fs_write_ext_block(ctx->fs,
+ ix->ei_leaf, eh);
+ }
+ } else {
+ char *block_buf;
+ struct ext3_extent_idx *ix;
+
+ ret = ext2fs_get_mem(ctx->fs->blocksize, &block_buf);
+ if (ret)
+ return ret;
+
+ ext_show_header(eh);
+ ix = EXT_FIRST_INDEX(eh);
+ for (item = 0; item < eh->eh_entries; item++, ix++) {
+ ext_show_index(ix);
+ /* index is processed first in e2fsck case */
+ if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+ !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
+ block_address = ix->ei_leaf;
+ flags = (*ctx->func)(ctx->fs, &block_address,
+ BLOCK_COUNT_IND, ref_block,
+ item, ctx->priv_data);
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags &(BLOCK_ABORT|BLOCK_ERROR);
+ goto free_buf;
+ }
+ if (flags & BLOCK_CHANGED) {
+ ret |= BLOCK_CHANGED;
+ /* index has no more block, remove it */
+ /* FIXME: 48-bit support */
+ ix->ei_leaf = block_address;
+ if (ix->ei_leaf == 0 &&
+ ix->ei_leaf_hi == 0) {
+ if(ext2fs_extent_index_remove(eh, ix)) {
+ ret |= BLOCK_ABORT |BLOCK_ERROR;
+ goto free_buf;
+ } else {
+ --item; --ix;
+ continue;
+ }
+ }
+ /* remapped? */
+ }
+ }
+ ctx->errcode = ext2fs_read_ext_block(ctx->fs,
+ ix->ei_leaf,
+ block_buf);
+ if (ctx->errcode) {
+ ret |= BLOCK_ERROR;
+ goto free_buf;
+ }
+ flags = block_iterate_extents(block_buf,
+ ctx->fs->blocksize,
+ ix->ei_leaf, item, ctx);
+ if (flags & BLOCK_CHANGED) {
+ struct ext3_extent_header *nh;
+ ctx->errcode =
+ ext2fs_write_ext_block(ctx->fs,
+ ix->ei_leaf,
+ block_buf);
+
+ nh = (struct ext3_extent_header *)block_buf;
+ if (nh->eh_entries == 0)
+ ix->ei_leaf = ix->ei_leaf_hi = 0;
+ }
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+ goto free_buf;
+ }
+ if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+ !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
+ flags = (*ctx->func)(ctx->fs, &block_address,
+ BLOCK_COUNT_IND, ref_block,
+ item, ctx->priv_data);
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags &(BLOCK_ABORT|BLOCK_ERROR);
+ goto free_buf;
+ }
+ if (flags & BLOCK_CHANGED)
+ /* FIXME: 48-bit support */
+ ix->ei_leaf = block_address;
+ }
+
+ if (flags & BLOCK_CHANGED) {
+ /* index has no more block, remove it */
+ if (ix->ei_leaf == 0 && ix->ei_leaf_hi == 0 &&
+ ext2fs_extent_index_remove(eh, ix)) {
+ ret |= BLOCK_ABORT |BLOCK_ERROR;
+ goto free_buf;
+ }
+
+ ret |= BLOCK_CHANGED;
+ if (ref_block == 0) {
+ --item; --ix;
+ continue;
+ }
+ /* remapped? */
+ }
+ }
+
+ free_buf:
+ ext2fs_free_mem(&block_buf);
+ }
+ return ret;
+}
Index: e2fsprogs-1.40.5/lib/ext2fs/ind_block.c
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/ind_block.c
+++ e2fsprogs-1.40.5/lib/ext2fs/ind_block.c
@@ -22,9 +22,9 @@
errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
{
errcode_t retval;
- blk_t *block_nr;
- int i;
- int limit = fs->blocksize >> 2;
+ int limit = fs->blocksize >> 2;
+ blk_t *block_nr = (blk_t *)buf;
+ int i;
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
(fs->io != fs->image_io))
@@ -35,7 +35,6 @@ errcode_t ext2fs_read_ind_block(ext2_fil
return retval;
}
#ifdef WORDS_BIGENDIAN
- block_nr = (blk_t *) buf;
for (i = 0; i < limit; i++, block_nr++)
*block_nr = ext2fs_swab32(*block_nr);
#endif
@@ -60,3 +59,82 @@ errcode_t ext2fs_write_ind_block(ext2_fi
}
+errcode_t ext2fs_read_ext_block(ext2_filsys fs, blk_t blk, void *buf)
+{
+ errcode_t retval;
+
+ if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
+ (fs->io != fs->image_io))
+ memset(buf, 0, fs->blocksize);
+ else {
+ retval = io_channel_read_blk(fs->io, blk, 1, buf);
+ if (retval)
+ return retval;
+ }
+#ifdef EXT2FS_ENABLE_SWAPFS
+ if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
+ struct ext3_extent_header *eh = buf;
+ int i, limit;
+
+ ext2fs_swap_extent_header(eh);
+
+ if (eh->eh_depth == 0) {
+ struct ext3_extent *ex = EXT_FIRST_EXTENT(eh);
+
+ limit = (fs->blocksize - sizeof(*eh)) / sizeof(*ex);
+ if (eh->eh_entries < limit)
+ limit = eh->eh_entries;
+
+ for (i = 0; i < limit; i++, ex++)
+ ext2fs_swap_extent(ex);
+ } else {
+ struct ext3_extent_idx *ix = EXT_FIRST_INDEX(eh);
+
+ limit = (fs->blocksize - sizeof(*eh)) / sizeof(*ix);
+ if (eh->eh_entries < limit)
+ limit = eh->eh_entries;
+
+ for (i = 0; i < limit; i++, ix++)
+ ext2fs_swap_extent_index(ix);
+ }
+ }
+#endif
+ return 0;
+}
+
+errcode_t ext2fs_write_ext_block(ext2_filsys fs, blk_t blk, void *buf)
+{
+ if (fs->flags & EXT2_FLAG_IMAGE_FILE)
+ return 0;
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+ if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
+ struct ext3_extent_header *eh = buf;
+ int i, limit;
+
+ if (eh->eh_depth == 0) {
+ struct ext3_extent *ex = EXT_FIRST_EXTENT(eh);
+
+ limit = (fs->blocksize - sizeof(*eh)) / sizeof(*ex);
+ if (eh->eh_entries < limit)
+ limit = eh->eh_entries;
+
+ for (i = 0; i < limit; i++, ex++)
+ ext2fs_swap_extent(ex);
+ } else {
+ struct ext3_extent_idx *ix = EXT_FIRST_INDEX(eh);
+
+ limit = (fs->blocksize - sizeof(*eh)) / sizeof(*ix);
+ if (eh->eh_entries < limit)
+ limit = eh->eh_entries;
+
+ for (i = 0; i < limit; i++, ix++)
+ ext2fs_swap_extent_index(ix);
+ }
+
+ ext2fs_swap_extent_header(eh);
+ }
+#endif
+ return io_channel_write_blk(fs->io, blk, 1, buf);
+}
+
Index: e2fsprogs-1.40.5/lib/ext2fs/swapfs.c
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/swapfs.c
+++ e2fsprogs-1.40.5/lib/ext2fs/swapfs.c
@@ -142,11 +142,33 @@ void ext2fs_swap_ext_attr(char *to, char
}
}
+void ext2fs_swap_extent_header(struct ext3_extent_header *eh) {
+ eh->eh_magic = ext2fs_swab16(eh->eh_magic);
+ eh->eh_entries = ext2fs_swab16(eh->eh_entries);
+ eh->eh_max = ext2fs_swab16(eh->eh_max);
+ eh->eh_depth = ext2fs_swab16(eh->eh_depth);
+ eh->eh_generation = ext2fs_swab32(eh->eh_generation);
+}
+
+void ext2fs_swap_extent_index(struct ext3_extent_idx *ix) {
+ ix->ei_block = ext2fs_swab32(ix->ei_block);
+ ix->ei_leaf = ext2fs_swab32(ix->ei_leaf);
+ ix->ei_leaf_hi = ext2fs_swab16(ix->ei_leaf_hi);
+ ix->ei_unused = ext2fs_swab16(ix->ei_unused);
+}
+
+void ext2fs_swap_extent(struct ext3_extent *ex) {
+ ex->ee_block = ext2fs_swab32(ex->ee_block);
+ ex->ee_len = ext2fs_swab16(ex->ee_len);
+ ex->ee_start_hi =ext2fs_swab16(ex->ee_start_hi);
+ ex->ee_start = ext2fs_swab32(ex->ee_start);
+}
+
void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
struct ext2_inode_large *f, int hostorder,
int bufsize)
{
- unsigned i, has_data_blocks, extra_isize;
+ unsigned i, has_data_blocks, extra_isize, has_extents;
int islnk = 0;
__u32 *eaf, *eat;
@@ -164,18 +186,46 @@ void ext2fs_swap_inode_full(ext2_filsys
t->i_gid = ext2fs_swab16(f->i_gid);
t->i_links_count = ext2fs_swab16(f->i_links_count);
t->i_file_acl = ext2fs_swab32(f->i_file_acl);
- if (hostorder)
- has_data_blocks = ext2fs_inode_data_blocks(fs,
+ if (hostorder) {
+ has_data_blocks = ext2fs_inode_data_blocks(fs,
(struct ext2_inode *) f);
- t->i_blocks = ext2fs_swab32(f->i_blocks);
- if (!hostorder)
- has_data_blocks = ext2fs_inode_data_blocks(fs,
+ t->i_blocks = ext2fs_swab32(f->i_blocks);
+ has_extents = (f->i_flags & EXT4_EXTENTS_FL);
+ t->i_flags = ext2fs_swab32(f->i_flags);
+ } else {
+ t->i_blocks = ext2fs_swab32(f->i_blocks);
+ has_data_blocks = ext2fs_inode_data_blocks(fs,
(struct ext2_inode *) t);
+ t->i_flags = ext2fs_swab32(f->i_flags);
+ has_extents = (t->i_flags & EXT4_EXTENTS_FL);
+ }
t->i_flags = ext2fs_swab32(f->i_flags);
t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
- if (!islnk || has_data_blocks ) {
- for (i = 0; i < EXT2_N_BLOCKS; i++)
- t->i_block[i] = ext2fs_swab32(f->i_block[i]);
+ if (!islnk || has_data_blocks) {
+ if (has_extents) {
+ struct ext3_extent_header *eh;
+ int max = EXT2_N_BLOCKS * sizeof(__u32) - sizeof(*eh);
+
+ memcpy(t->i_block, f->i_block, sizeof(f->i_block));
+ eh = (struct ext3_extent_header *)t->i_block;
+ ext2fs_swap_extent_header(eh);
+
+ if (!eh->eh_depth) {
+ struct ext3_extent *ex = EXT_FIRST_EXTENT(eh);
+ max = max / sizeof(struct ext3_extent);
+ for (i = 0; i < max; i++, ex++)
+ ext2fs_swap_extent(ex);
+ } else {
+ struct ext3_extent_idx *ix =
+ EXT_FIRST_INDEX(eh);
+ max = max / sizeof(struct ext3_extent_idx);
+ for (i = 0; i < max; i++, ix++)
+ ext2fs_swap_extent_index(ix);
+ }
+ } else {
+ for (i = 0; i < EXT2_N_BLOCKS; i++)
+ t->i_block[i] = ext2fs_swab32(f->i_block[i]);
+ }
} else if (t != f) {
for (i = 0; i < EXT2_N_BLOCKS; i++)
t->i_block[i] = f->i_block[i];
@@ -218,11 +268,13 @@ void ext2fs_swap_inode_full(ext2_filsys
if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
return; /* no i_extra_isize field */
- if (hostorder)
+ if (hostorder) {
extra_isize = f->i_extra_isize;
- t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
- if (!hostorder)
+ t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
+ } else {
+ t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
extra_isize = t->i_extra_isize;
+ }
if (extra_isize > EXT2_INODE_SIZE(fs->super) -
sizeof(struct ext2_inode)) {
/* this is error case: i_extra_size is too large */
Index: e2fsprogs-1.40.5/lib/ext2fs/valid_blk.c
===================================================================
--- e2fsprogs-1.40.5.orig/lib/ext2fs/valid_blk.c
+++ e2fsprogs-1.40.5/lib/ext2fs/valid_blk.c
@@ -19,6 +19,7 @@
#include "ext2_fs.h"
#include "ext2fs.h"
+#include "ext3_extents.h"
/*
* This function returns 1 if the inode's block entries actually
@@ -41,12 +42,23 @@ int ext2fs_inode_has_valid_blocks(struct
if (LINUX_S_ISLNK (inode->i_mode)) {
if (inode->i_file_acl == 0) {
/* With no EA block, we can rely on i_blocks */
- if (inode->i_blocks == 0)
- return 0;
+ if (inode->i_flags & EXT4_EXTENTS_FL) {
+ struct ext3_extent_header *eh;
+ eh = (struct ext3_extent_header *)inode->i_block;
+ if (eh->eh_entries == 0)
+ return 0;
+ } else {
+ if (inode->i_blocks == 0)
+ return 0;
+ }
} else {
/* With an EA block, life gets more tricky */
if (inode->i_size >= EXT2_N_BLOCKS*4)
return 1; /* definitely using i_block[] */
+ /*
+ * we cant have EA + extents, so assume we aren't
+ * using extents
+ */
if (inode->i_size > 4 && inode->i_block[1] == 0)
return 1; /* definitely using i_block[] */
return 0; /* Probably a fast symlink */
Index: e2fsprogs-1.40.5/tests/f_bad_disconnected_inode/expect.1
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_bad_disconnected_inode/expect.1
+++ e2fsprogs-1.40.5/tests/f_bad_disconnected_inode/expect.1
@@ -1,4 +1,10 @@
Pass 1: Checking inodes, blocks, and sizes
+Inode 15 has EXTENT_FL set, but is not in extents format
+Fix? yes
+
+Inode 16 has EXTENT_FL set, but is not in extents format
+Fix? yes
+
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
/lost+found not found. Create? yes
Index: e2fsprogs-1.40.5/tests/f_bbfile/expect.1
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_bbfile/expect.1
+++ e2fsprogs-1.40.5/tests/f_bbfile/expect.1
@@ -3,46 +3,60 @@ Filesystem did not have a UUID; generati
Pass 1: Checking inodes, blocks, and sizes
Group 0's inode bitmap (4) is bad. Relocate? yes
+Inode 11 has corrupt indirect block
+Clear? yes
+
Relocating group 0's inode bitmap from 4 to 43...
+Restarting e2fsck from the beginning...
+Pass 1: Checking inodes, blocks, and sizes
Running additional passes to resolve blocks claimed by more than one inode...
Pass 1B: Rescanning for multiply-claimed blocks
Multiply-claimed block(s) in inode 2: 21
-Multiply-claimed block(s) in inode 11: 9 10 11 12 13 14 15 16 17 18 19 20
Multiply-claimed block(s) in inode 12: 25 26
Pass 1C: Scanning directories for inodes with multiply-claimed blocks
Pass 1D: Reconciling multiply-claimed blocks
-(There are 3 inodes containing multiply-claimed blocks.)
+(There are 2 inodes containing multiply-claimed blocks.)
File / (inode #2, mod time Sun Jan 2 08:29:13 1994)
has 1 multiply-claimed block(s), shared with 1 file(s):
<The bad blocks inode> (inode #1, mod time Sun Jul 17 00:47:58 1994)
Clone multiply-claimed blocks? yes
-File /lost+found (inode #11, mod time Sun Jan 2 08:28:40 1994)
- has 12 multiply-claimed block(s), shared with 1 file(s):
- <The bad blocks inode> (inode #1, mod time Sun Jul 17 00:47:58 1994)
-Clone multiply-claimed blocks? yes
-
File /termcap (inode #12, mod time Sun Jan 2 08:29:13 1994)
has 2 multiply-claimed block(s), shared with 1 file(s):
<The bad blocks inode> (inode #1, mod time Sun Jul 17 00:47:58 1994)
Clone multiply-claimed blocks? yes
Pass 2: Checking directory structure
+Entry 'lost+found' in / (2) has deleted/unused inode 11. Clear? yes
+
Pass 3: Checking directory connectivity
+/lost+found not found. Create? yes
+
Pass 4: Checking reference counts
+Inode 2 ref count is 4, should be 3. Fix? yes
+
Pass 5: Checking group summary information
Block bitmap differences: +43
Fix? yes
-Free blocks count wrong for group #0 (57, counted=41).
+Free blocks count wrong for group #0 (56, counted=52).
+Fix? yes
+
+Free blocks count wrong (56, counted=52).
+Fix? yes
+
+Free inodes count wrong for group #0 (19, counted=20).
+Fix? yes
+
+Directories count wrong for group #0 (3, counted=2).
Fix? yes
-Free blocks count wrong (57, counted=41).
+Free inodes count wrong (19, counted=20).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 12/32 files (0.0% non-contiguous), 59/100 blocks
+test_filesys: 12/32 files (0.0% non-contiguous), 48/100 blocks
Exit status is 1
Index: e2fsprogs-1.40.5/tests/f_bbfile/expect.2
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_bbfile/expect.2
+++ e2fsprogs-1.40.5/tests/f_bbfile/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: 12/32 files (8.3% non-contiguous), 59/100 blocks
+test_filesys: 12/32 files (8.3% non-contiguous), 48/100 blocks
Exit status is 0
Index: e2fsprogs-1.40.5/tests/f_lotsbad/expect.1
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_lotsbad/expect.1
+++ e2fsprogs-1.40.5/tests/f_lotsbad/expect.1
@@ -8,54 +8,41 @@ Inode 13, i_size is 15360, should be 122
Inode 13, i_blocks is 32, should be 30. Fix? yes
-Inode 12 has illegal block(s). Clear? yes
+Inode 12 has corrupt indirect block
+Clear? yes
-Illegal block #12 (778398818) in inode 12. CLEARED.
-Illegal block #13 (1768444960) in inode 12. CLEARED.
-Illegal block #14 (1752375411) in inode 12. CLEARED.
-Illegal block #15 (1684829551) in inode 12. CLEARED.
-Illegal block #16 (1886349344) in inode 12. CLEARED.
-Illegal block #17 (1819633253) in inode 12. CLEARED.
-Illegal block #18 (1663072620) in inode 12. CLEARED.
-Illegal block #19 (1735287144) in inode 12. CLEARED.
-Illegal block #20 (1310731877) in inode 12. CLEARED.
-Illegal block #21 (560297071) in inode 12. CLEARED.
-Illegal block #22 (543512352) in inode 12. CLEARED.
-Too many illegal blocks in inode 12.
-Clear inode? yes
+Inode 12, i_blocks is 34, should be 24. Fix? yes
-Restarting e2fsck from the beginning...
-Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
-Entry 'termcap' in / (2) has deleted/unused inode 12. Clear? yes
+Directory inode 13 has an unallocated block #16580876. Allocate? 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) -(74--90)
+Block bitmap differences: -(38--41) -(74--90)
Fix? yes
-Free blocks count wrong for group #0 (9, counted=43).
+Free blocks count wrong for group #0 (9, counted=30).
Fix? yes
-Free blocks count wrong (9, counted=43).
+Free blocks count wrong (9, counted=30).
Fix? yes
-Inode bitmap differences: -12 -14
+Inode bitmap differences: -14
Fix? yes
-Free inodes count wrong for group #0 (18, counted=20).
+Free inodes count wrong for group #0 (18, counted=19).
Fix? yes
Directories count wrong for group #0 (4, counted=3).
Fix? yes
-Free inodes count wrong (18, counted=20).
+Free inodes count wrong (18, counted=19).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 12/32 files (0.0% non-contiguous), 57/100 blocks
+test_filesys: 13/32 files (7.7% non-contiguous), 70/100 blocks
Exit status is 1
Index: e2fsprogs-1.40.5/tests/f_lotsbad/expect.2
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_lotsbad/expect.2
+++ e2fsprogs-1.40.5/tests/f_lotsbad/expect.2
@@ -1,7 +1,18 @@
Pass 1: Checking inodes, blocks, and sizes
+Inode 13 is too big. Truncate? yes
+
+Block #16580876 (37) causes directory to be too big. CLEARED.
+Inode 13, i_size is 4093916160, should be 12288. Fix? yes
+
+Inode 13, i_blocks is 32, should be 30. Fix? yes
+
Pass 2: Checking directory structure
+Directory inode 13 has an unallocated block #16580876. Allocate? yes
+
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
-test_filesys: 12/32 files (0.0% non-contiguous), 57/100 blocks
-Exit status is 0
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/32 files (15.4% non-contiguous), 70/100 blocks
+Exit status is 1
Index: e2fsprogs-1.40.5/tests/f_messy_inode/expect.1
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_messy_inode/expect.1
+++ e2fsprogs-1.40.5/tests/f_messy_inode/expect.1
@@ -1,38 +1,36 @@
Filesystem did not have a UUID; generating one.
Pass 1: Checking inodes, blocks, and sizes
-Inode 14 has illegal block(s). Clear? yes
-
-Illegal block #2 (4294901760) in inode 14. CLEARED.
-Illegal block #3 (4294901760) in inode 14. CLEARED.
-Illegal block #4 (4294901760) in inode 14. CLEARED.
-Illegal block #5 (4294901760) in inode 14. CLEARED.
-Illegal block #6 (4294901760) in inode 14. CLEARED.
-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
+Inode 14 has corrupt indirect block
+Clear? yes
+Restarting e2fsck from the beginning...
+Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
-i_file_acl for inode 14 (/MAKEDEV) is 4294901760, should be zero.
-Clear? yes
+Entry 'MAKEDEV' in / (2) has deleted/unused inode 14. Clear? yes
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
-Block bitmap differences: -(43--49)
+Block bitmap differences: -(41--49)
+Fix? yes
+
+Free blocks count wrong for group #0 (68, counted=77).
+Fix? yes
+
+Free blocks count wrong (68, counted=77).
+Fix? yes
+
+Inode bitmap differences: -14
Fix? yes
-Free blocks count wrong for group #0 (68, counted=75).
+Free inodes count wrong for group #0 (3, counted=4).
Fix? yes
-Free blocks count wrong (68, counted=75).
+Free inodes count wrong (3, counted=4).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 29/32 files (3.4% non-contiguous), 25/100 blocks
+test_filesys: 28/32 files (0.0% non-contiguous), 23/100 blocks
Exit status is 1
Index: e2fsprogs-1.40.5/tests/f_messy_inode/expect.2
===================================================================
--- e2fsprogs-1.40.5.orig/tests/f_messy_inode/expect.2
+++ e2fsprogs-1.40.5/tests/f_messy_inode/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: 29/32 files (0.0% non-contiguous), 25/100 blocks
+test_filesys: 28/32 files (0.0% non-contiguous), 23/100 blocks
Exit status is 0
Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.
-
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists