2009-11-29 20:33:45

by Theodore Ts'o

[permalink] [raw]
Subject: [PATCH 1/5] e2fsck: detect holes in extent-mapped directories

Directories are not allowed to be sparse; the code for scanning
extent-mapped directories was not calling ext2fs_add_dir_block() for
missing directory blocks, so we weren't catching this form of file
system corruption. Fix this.

Signed-off-by: "Theodore Ts'o" <[email protected]>
---
e2fsck/pass1.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index d2021dd..a241c23 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1725,6 +1725,16 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
}
pb->fragmented = 1;
}
+ while (is_dir && ++pb->last_db_block < extent.e_lblk) {
+ pctx->errcode = ext2fs_add_dir_block(ctx->fs->dblist,
+ pb->ino, 0,
+ pb->last_db_block);
+ if (pctx->errcode) {
+ pctx->blk = 0;
+ pctx->num = pb->last_db_block;
+ goto failed_add_dir_block;
+ }
+ }
for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0;
i < extent.e_len;
blk++, blockcnt++, i++) {
@@ -1735,6 +1745,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
if (pctx->errcode) {
pctx->blk = blk;
pctx->num = blockcnt;
+ failed_add_dir_block:
fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
/* Should never get here */
ctx->flags |= E2F_FLAG_ABORT;
@@ -1742,6 +1753,8 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
}
}
}
+ if (is_dir && extent.e_len > 0)
+ pb->last_db_block = blockcnt - 1;
pb->num_blocks += extent.e_len;
pb->previous_block = extent.e_pblk + extent.e_len - 1;
start_block = extent.e_lblk + extent.e_len - 1;
--
1.6.5.216.g5288a.dirty



2009-11-29 20:33:56

by Theodore Ts'o

[permalink] [raw]
Subject: [PATCH 2/5] libext2fs: Fix SET_BMAP bugs in ext2fs_bmap() and ext2fs_bmap2()

Don't byte-swap the block number when setting i_block[x], since the
write_inode function will take of byte swapping the inode.

The phys_blk parameter contains an input parameter in the SET_BMAP
case, so it must be passed to ext2fs_bmap2() from the legacy function
ext2fs_bmap().

Signed-off-by: "Theodore Ts'o" <[email protected]>
---
lib/ext2fs/bmap.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 2a86439..933036b 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -214,9 +214,6 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
if (block < EXT2_NDIR_BLOCKS) {
if (bmap_flags & BMAP_SET) {
b = *phys_blk;
-#ifdef WORDS_BIGENDIAN
- b = ext2fs_swab32(b);
-#endif
inode_bmap(inode, block) = b;
inode_dirty++;
goto done;
@@ -325,7 +322,7 @@ errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
blk_t *phys_blk)
{
errcode_t ret;
- blk64_t ret_blk;
+ blk64_t ret_blk = *phys_blk;

ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block,
0, &ret_blk);
--
1.6.5.216.g5288a.dirty


2009-11-29 20:34:06

by Theodore Ts'o

[permalink] [raw]
Subject: [PATCH 3/5] e2fsck: Fix block allocation for holes in extent-mapped directories

In pass 2, when allocating new blocks for holes in directories, use
ext2fs_set_bmap() instead of ext2fs_block_iterate2() with a helper
function so that the newly allocated directory blocks are correctly
assigned in extent-mapped directories.

Signed-off-by: "Theodore Ts'o" <[email protected]>
---
e2fsck/pass2.c | 30 ++----------------------------
1 files changed, 2 insertions(+), 28 deletions(-)

diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 889e39d..761c2f1 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -66,12 +66,6 @@ static int check_dir_block(ext2_filsys fs,
static int allocate_dir_block(e2fsck_t ctx,
struct ext2_db_entry *dir_blocks_info,
char *buf, struct problem_context *pctx);
-static int update_dir_block(ext2_filsys fs,
- blk_t *block_nr,
- e2_blkcnt_t blockcnt,
- blk_t ref_block,
- int ref_offset,
- void *priv_data);
static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
static int htree_depth(struct dx_dir_info *dx_dir,
struct dx_dirblock_info *dx_db);
@@ -1463,8 +1457,8 @@ static int allocate_dir_block(e2fsck_t ctx,
* Finally, update the block pointers for the inode
*/
db->blk = blk;
- pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
- 0, update_dir_block, db);
+ pctx->errcode = ext2fs_bmap(fs, db->ino, &inode, 0, BMAP_SET,
+ db->blockcnt, &blk);
if (pctx->errcode) {
pctx->str = "ext2fs_block_iterate";
fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
@@ -1473,23 +1467,3 @@ static int allocate_dir_block(e2fsck_t ctx,

return 0;
}
-
-/*
- * This is a helper function for allocate_dir_block().
- */
-static int update_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
- blk_t *block_nr,
- e2_blkcnt_t blockcnt,
- blk_t ref_block EXT2FS_ATTR((unused)),
- int ref_offset EXT2FS_ATTR((unused)),
- void *priv_data)
-{
- struct ext2_db_entry *db;

2009-11-29 20:34:17

by Theodore Ts'o

[permalink] [raw]
Subject: [PATCH 4/5] e2fsck: Don't rehash directories which can fit in a single directory block

Signed-off-by: "Theodore Ts'o" <[email protected]>
---
e2fsck/rehash.c | 12 ++++++++++++
tests/f_dup_de/expect.1 | 12 ++++++------
tests/f_dup_de/expect.2 | 2 +-
3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 46d04e4..780742e 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -736,6 +736,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
fd.compress = 1;
fd.parent = 0;

+retry_nohash:
/* Read in the entire directory into memory */
retval = ext2fs_block_iterate2(fs, ino, 0, 0,
fill_dir_block, &fd);
@@ -744,6 +745,17 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
goto errout;
}

+ /*
+ * If the entries read are less than a block, then don't index
+ * the directory
+ */
+ if (!fd.compress && (fd.dir_size < (fs->blocksize - 24))) {
+ fd.compress = 1;
+ fd.dir_size = 0;
+ fd.num_array = 0;
+ goto retry_nohash;
+ }
+
#if 0
printf("%d entries (%d bytes) found in inode %d\n",
fd.num_array, fd.dir_size, ino);
diff --git a/tests/f_dup_de/expect.1 b/tests/f_dup_de/expect.1
index 78545cc..e421547 100644
--- a/tests/f_dup_de/expect.1
+++ b/tests/f_dup_de/expect.1
@@ -5,24 +5,24 @@ Duplicate entry 'mailcap.dpkg-old' found.

Pass 3: Checking directory connectivity
Pass 3A: Optimizing directories
-Duplicate entry 'mailcap.dpkg-old' in /etc (12) found. Clear? yes
-
Duplicate entry 'fstab' in /etc (12) found. Clear? yes

Duplicate entry 'localtime' in /etc (12) found. Clear? yes

-Duplicate entry 'resolv.conf' in /etc (12) found. Clear? yes
-
-Duplicate entry 'usb.permissions' in /etc (12) found. Clear? yes
+Duplicate entry 'mailcap.dpkg-old' in /etc (12) found. Clear? yes

Duplicate entry 'modules.conf.old' in /etc (12) found. Clear? yes

Entry 'modules.conf.old' in /etc (12) has a non-unique filename.
Rename to modules.conf.o~0? yes

+Duplicate entry 'resolv.conf' in /etc (12) found. Clear? yes
+
+Duplicate entry 'usb.permissions' in /etc (12) found. Clear? yes
+
Pass 4: Checking reference counts
Pass 5: Checking group summary information

test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 18/2048 files (5.6% non-contiguous), 325/330 blocks
+test_filesys: 18/2048 files (5.6% non-contiguous), 324/330 blocks
Exit status is 1
diff --git a/tests/f_dup_de/expect.2 b/tests/f_dup_de/expect.2
index e3accc6..4d680af 100644
--- a/tests/f_dup_de/expect.2
+++ b/tests/f_dup_de/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: 18/2048 files (5.6% non-contiguous), 325/330 blocks
+test_filesys: 18/2048 files (5.6% non-contiguous), 324/330 blocks
Exit status is 0
--
1.6.5.216.g5288a.dirty


2009-11-29 20:34:28

by Theodore Ts'o

[permalink] [raw]
Subject: [PATCH 5/5] e2fsck: Try to update on-disk bitmap in e2fsck_get_alloc_block() callback

The e2fsck_get_alloc_block() callback is used so that if the ext2fs
library needs to allocate blocks internally (most notably by the
extents functions), e2fsck's internal block usage map is consulted
since it is the only thing that can be trusted during a large part of
e2fsck's operation.

Change it to update the on-disk bitmap if it is loaded. This reduces
the number of spurious differences found in pass #5.

Signed-off-by: "Theodore Ts'o" <[email protected]>
---
e2fsck/pass1.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index a241c23..0cb3fda 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -2628,6 +2628,10 @@ static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal,
ctx->block_found_map, &new_block);
if (retval)
return retval;
+ if (fs->block_map) {
+ ext2fs_mark_block_bitmap(fs->block_map, new_block);
+ ext2fs_mark_bb_dirty(fs);
+ }
} else {
if (!fs->block_map) {
retval = ext2fs_read_block_bitmap(fs);
--
1.6.5.216.g5288a.dirty