[PATCH 16/21] e2fsck: do a better job of fixing i_size of inline directories

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If we encounter a directory whose i_size != the inline data size, just
set i_size to the size of the inline data.  The pb.last_block
calculation is wrong since pb.last_block == -1, which results in
i_size being set to zero, which corrupts the directory.

Clear the inline_data inode flag if we actually /are/ setting i_size
to zero.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 e2fsck/pass1.c |   22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)


diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index b214f72..1a9e0d5 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -2832,17 +2832,21 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 		if (inode->i_flags & EXT4_INLINE_DATA_FL) {
 			int flags;
 			size_t size;
+			errcode_t err;
 
+			size = 0;
 			flags = ctx->fs->flags;
 			ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
-			if (ext2fs_inline_data_size(ctx->fs, pctx->ino, &size))
-				bad_size = 5;
+			err = ext2fs_inline_data_size(ctx->fs, pctx->ino,
+						      &size);
 			ctx->fs->flags = (flags &
 					  EXT2_FLAG_IGNORE_CSUM_ERRORS) |
 					 (ctx->fs->flags &
 					  ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
-			if (size != inode->i_size)
-				bad_size = 5;
+			if (err || size != inode->i_size) {
+				bad_size = 7;
+				pctx->num = size;
+			}
 		} else if (inode->i_size & (fs->blocksize - 1))
 			bad_size = 5;
 		else if (nblock > (pb.last_block + 1))
@@ -2875,12 +2879,20 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 	}
 	/* i_size for symlinks is checked elsewhere */
 	if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
-		pctx->num = (pb.last_block+1) * fs->blocksize;
+		/* Did inline_data set pctx->num earlier? */
+		if (bad_size != 7)
+			pctx->num = (pb.last_block + 1) * fs->blocksize;
 		pctx->group = bad_size;
 		if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
 			if (LINUX_S_ISDIR(inode->i_mode))
 				pctx->num &= 0xFFFFFFFFULL;
 			ext2fs_inode_size_set(fs, inode, pctx->num);
+			if (EXT2_I_SIZE(inode) == 0 &&
+			    (inode->i_flags & EXT4_INLINE_DATA_FL)) {
+				memset(inode->i_block, 0,
+				       sizeof(inode->i_block));
+				inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+			}
 			dirty_inode++;
 		}
 		pctx->num = 0;

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux