From 2cd12338395fda301826a88ec7005f4362cc756e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 13 Mar 2008 00:58:54 -0400 Subject: [PATCH] e2fsck: Fix directory i_size handling If a directory's i_size is bigger than the number of blocks, don't try to allocate extra empty blocks to the end of the directory; there's no real point to do that. Also, if a directory's i_size is not a multiple of the blocksize, flag that as a mistake so it can be fixed. This more elegantly addresses the problem which was found on Bas van Schaik's filesystem. Signed-off-by: "Theodore Ts'o" --- e2fsck/pass1.c | 25 ++++++++++++++++++++++++- tests/f_holedir/expect.1 | 13 ++++++++++--- tests/f_holedir/expect.2 | 2 +- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index b4db8efc..839f099d 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -1546,6 +1546,26 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, goto out; } + if (pb.is_dir) { + while (1) { + struct ext2_db_entry *entry; + + if (ext2fs_dblist_get_last(fs->dblist, &entry) || + (entry->ino != ino) || + (entry->blk != 0) || + (entry->blockcnt == 0)) + break; + /* printf("Dropping ino %lu blk %lu blockcnt %d\n", + entry->ino, entry->blk, entry->blockcnt); */ + ext2fs_dblist_drop_last(fs->dblist); + if (ext2fs_dblist_get_last(fs->dblist, &entry) || + (entry->ino != ino)) + pb.last_block--; + else + pb.last_block = entry->blockcnt; + } + } + if (inode->i_flags & EXT2_INDEX_FL) { if (handle_htree(ctx, pctx, ino, inode, block_buf)) { inode->i_flags &= ~EXT2_INDEX_FL; @@ -1583,7 +1603,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, #endif if (pb.is_dir) { int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); - if (nblock > (pb.last_block + 1)) + if (inode->i_size & (fs->blocksize - 1)) + bad_size = 5; + else if (nblock > (pb.last_block + 1)) bad_size = 1; else if (nblock < (pb.last_block + 1)) { if (((pb.last_block + 1) - nblock) > @@ -1745,6 +1767,7 @@ static int process_block(ext2_filsys fs, printf("Missing block (#%d) in directory inode %lu!\n", blockcnt, p->ino); #endif + p->last_block = blockcnt; goto mark_dir; } return 0; diff --git a/tests/f_holedir/expect.1 b/tests/f_holedir/expect.1 index 05e0cbbc..ad74fa6d 100644 --- a/tests/f_holedir/expect.1 +++ b/tests/f_holedir/expect.1 @@ -15,12 +15,19 @@ Directory inode 11 has an unallocated block #3. Allocate? yes Directory inode 11 has an unallocated block #6. Allocate? yes -Directory inode 11 has an unallocated block #11. Allocate? yes - Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information +Block bitmap differences: -21 +Fix? yes + +Free blocks count wrong for group #0 (78, counted=79). +Fix? yes + +Free blocks count wrong (78, counted=79). +Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 11/32 files (9.1% non-contiguous), 22/100 blocks +test_filesys: 11/32 files (9.1% non-contiguous), 21/100 blocks Exit status is 1 diff --git a/tests/f_holedir/expect.2 b/tests/f_holedir/expect.2 index a821f878..4c0b4f28 100644 --- a/tests/f_holedir/expect.2 +++ b/tests/f_holedir/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: 11/32 files (0.0% non-contiguous), 22/100 blocks +test_filesys: 11/32 files (0.0% non-contiguous), 21/100 blocks Exit status is 0