From 47b8941774df6bc134efd6d6051af33391fa3078 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 31 Jan 2017 14:05:45 -0500 Subject: [PATCH] e2fsck: make sure system.data xattr is present E2fsprogs used to assume that if i_size is less than 60 bytes, the system.data xattr isn't needed (and should be removed). The kernel disagree, and will declare the file system to be corrupted. Enforce the tighter constraints assumed by the kernel. Signed-off-by: Theodore Ts'o --- e2fsck/pass1.c | 9 ++++----- lib/ext2fs/inline_data.c | 8 ++++---- tests/f_write_ea_no_extra_isize/expect.1 | 23 ++++++++++++++++++++--- tests/f_write_ea_no_extra_isize/expect.2 | 2 +- tests/f_write_ea_toobig_extra_isize/expect.1 | 23 ++++++++++++++++++++--- tests/f_write_ea_toobig_extra_isize/expect.2 | 2 +- tests/f_write_ea_toosmall_extra_isize/expect.1 | 23 ++++++++++++++++++++--- tests/f_write_ea_toosmall_extra_isize/expect.2 | 2 +- util/gen-sample-fs | 24 +++++++++++++++++------- 9 files changed, 88 insertions(+), 28 deletions(-) mode change 100644 => 100755 util/gen-sample-fs diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 8ef40f6..f13809e 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -1359,7 +1359,6 @@ void e2fsck_pass1(e2fsck_t ctx) /* Test for inline data flag but no attr */ if ((inode->i_flags & EXT4_INLINE_DATA_FL) && inlinedata_fs && - EXT2_I_SIZE(inode) > EXT4_MIN_INLINE_DATA_SIZE && (ino >= EXT2_FIRST_INODE(fs->super))) { size_t size = 0; errcode_t err; @@ -1393,15 +1392,15 @@ void e2fsck_pass1(e2fsck_t ctx) /* broken EA or no system.data EA; truncate */ if (fix_problem(ctx, PR_1_INLINE_DATA_NO_ATTR, &pctx)) { - err = ext2fs_inode_size_set(fs, inode, - sizeof(inode->i_block)); + err = ext2fs_inode_size_set(fs, inode, 0); if (err) { pctx.errcode = err; ctx->flags |= E2F_FLAG_ABORT; goto endit; } - if (LINUX_S_ISLNK(inode->i_mode)) - inode->i_flags &= ~EXT4_INLINE_DATA_FL; + inode->i_flags &= ~EXT4_INLINE_DATA_FL; + memset(&inode->i_block, 0, + sizeof(inode->i_block)); e2fsck_write_inode(ctx, ino, inode, "pass1"); failed_csum = 0; diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c index c8613f6..c0fc4ed 100644 --- a/lib/ext2fs/inline_data.c +++ b/lib/ext2fs/inline_data.c @@ -557,9 +557,6 @@ errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, } if (size <= EXT4_MIN_INLINE_DATA_SIZE) { - retval = ext2fs_inline_data_ea_remove(fs, ino); - if (retval) - return retval; memcpy((void *)inode->i_block, buf, size); return ext2fs_write_inode(fs, ino, inode); } @@ -587,7 +584,10 @@ errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, return retval; data.fs = fs; data.ino = ino; - data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; + if (size > EXT4_MIN_INLINE_DATA_SIZE) + data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; + else + data.ea_size = 0; data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE; return ext2fs_inline_data_ea_set(&data); } diff --git a/tests/f_write_ea_no_extra_isize/expect.1 b/tests/f_write_ea_no_extra_isize/expect.1 index b7e7438..43d7d36 100644 --- a/tests/f_write_ea_no_extra_isize/expect.1 +++ b/tests/f_write_ea_no_extra_isize/expect.1 @@ -1,12 +1,29 @@ Pass 1: Checking inodes, blocks, and sizes +Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes + +Inode 12 is a zero-length directory. Clear? yes + Pass 2: Checking directory structure -Directory inode 12, block #0, offset 4: directory corrupted -Salvage? yes +Entry 'x' in / (2) has deleted/unused inode 12. Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts +Inode 2 ref count is 4, should be 3. Fix? yes + Pass 5: Checking group summary information +Inode bitmap differences: -12 +Fix? yes + +Free inodes count wrong for group #0 (116, counted=117). +Fix? yes + +Directories count wrong for group #0 (3, counted=2). +Fix? yes + +Free inodes count wrong (116, counted=117). +Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks +test_filesys: 11/128 files (0.0% non-contiguous), 17/512 blocks Exit status is 1 diff --git a/tests/f_write_ea_no_extra_isize/expect.2 b/tests/f_write_ea_no_extra_isize/expect.2 index 3b6073e..8025ccb 100644 --- a/tests/f_write_ea_no_extra_isize/expect.2 +++ b/tests/f_write_ea_no_extra_isize/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/128 files (0.0% non-contiguous), 17/512 blocks +test_filesys: 11/128 files (0.0% non-contiguous), 17/512 blocks Exit status is 0 diff --git a/tests/f_write_ea_toobig_extra_isize/expect.1 b/tests/f_write_ea_toobig_extra_isize/expect.1 index 4aa86ac..fc9ba6c 100644 --- a/tests/f_write_ea_toobig_extra_isize/expect.1 +++ b/tests/f_write_ea_toobig_extra_isize/expect.1 @@ -1,15 +1,32 @@ Pass 1: Checking inodes, blocks, and sizes +Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes + Inode 12 has a extra size (126) which is invalid Fix? yes +Inode 12 is a zero-length directory. Clear? yes + Pass 2: Checking directory structure -Directory inode 12, block #0, offset 4: directory corrupted -Salvage? yes +Entry 'x' in / (2) has deleted/unused inode 12. Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts +Inode 2 ref count is 4, should be 3. Fix? yes + Pass 5: Checking group summary information +Inode bitmap differences: -12 +Fix? yes + +Free inodes count wrong for group #0 (116, counted=117). +Fix? yes + +Directories count wrong for group #0 (3, counted=2). +Fix? yes + +Free inodes count wrong (116, counted=117). +Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks +test_filesys: 11/128 files (0.0% non-contiguous), 17/512 blocks Exit status is 1 diff --git a/tests/f_write_ea_toobig_extra_isize/expect.2 b/tests/f_write_ea_toobig_extra_isize/expect.2 index 3b6073e..8025ccb 100644 --- a/tests/f_write_ea_toobig_extra_isize/expect.2 +++ b/tests/f_write_ea_toobig_extra_isize/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/128 files (0.0% non-contiguous), 17/512 blocks +test_filesys: 11/128 files (0.0% non-contiguous), 17/512 blocks Exit status is 0 diff --git a/tests/f_write_ea_toosmall_extra_isize/expect.1 b/tests/f_write_ea_toosmall_extra_isize/expect.1 index eecfc9d..8d9381e 100644 --- a/tests/f_write_ea_toosmall_extra_isize/expect.1 +++ b/tests/f_write_ea_toosmall_extra_isize/expect.1 @@ -1,15 +1,32 @@ Pass 1: Checking inodes, blocks, and sizes +Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes + Inode 12 has a extra size (1) which is invalid Fix? yes +Inode 12 is a zero-length directory. Clear? yes + Pass 2: Checking directory structure -Directory inode 12, block #0, offset 4: directory corrupted -Salvage? yes +Entry 'x' in / (2) has deleted/unused inode 12. Clear? yes Pass 3: Checking directory connectivity Pass 4: Checking reference counts +Inode 2 ref count is 4, should be 3. Fix? yes + Pass 5: Checking group summary information +Inode bitmap differences: -12 +Fix? yes + +Free inodes count wrong for group #0 (116, counted=117). +Fix? yes + +Directories count wrong for group #0 (3, counted=2). +Fix? yes + +Free inodes count wrong (116, counted=117). +Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks +test_filesys: 11/128 files (0.0% non-contiguous), 17/512 blocks Exit status is 1 diff --git a/tests/f_write_ea_toosmall_extra_isize/expect.2 b/tests/f_write_ea_toosmall_extra_isize/expect.2 index 3b6073e..8025ccb 100644 --- a/tests/f_write_ea_toosmall_extra_isize/expect.2 +++ b/tests/f_write_ea_toosmall_extra_isize/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/128 files (0.0% non-contiguous), 17/512 blocks +test_filesys: 11/128 files (0.0% non-contiguous), 17/512 blocks Exit status is 0 diff --git a/util/gen-sample-fs b/util/gen-sample-fs old mode 100644 new mode 100755 index a6d7b31..8e13916 --- a/util/gen-sample-fs +++ b/util/gen-sample-fs @@ -4,10 +4,10 @@ MNT=/mnt FS=/tmp/foo.img cp /dev/null $FS -mke2fs -t ext4 -O inline_data -I 256 -b 4096 $FS 256 +mke2fs -q -t ext4 -O inline_data,^has_journal -I 256 -b 4096 -N 64 $FS 256 mount -t ext4 $FS $MNT ln -s symlink_data $MNT/symlink -for i in 30 70 500 1023 1024 1500; do +for i in 30 70 500 1023 1024; do ln -s /$(perl -e "print 'x' x $i;") $MNT/l_$i done touch $MNT/acl @@ -18,13 +18,23 @@ setfacl -m g:daemon:r $MNT/acl touch $MNT/simple_acl setfacl -m u:daemon:r $MNT/simple_acl touch $MNT/xattr -attr -s foo -V bar $MNT/xattr -echo -e "one\n\ttwo" | attr -s quux $MNT/xattr -echo -e "abc\001\002\003" | attr -s def $MNT/xattr +attr -q -s foo -V bar $MNT/xattr +echo -e "one\n\ttwo" | attr -q -s quux $MNT/xattr +echo -e "abc\001\002\003" | attr -q -s def $MNT/xattr echo file_data > $MNT/small_inline a="I am a very model of a modern major general;" a="$a I've information vegetable, animal and mineral" echo $a > $MNT/big_inline +mkdir $MNT/sdir +touch $MNT/sdir/1 +touch $MNT/sdir/2 +touch $MNT/sdir/3 +touch $MNT/sdir/4 +mkdir $MNT/mdir +touch $MNT/mdir/1 +touch $MNT/mdir/2 +touch $MNT/mdir/3 +touch $MNT/mdir/4 +touch $MNT/mdir/5 umount $MNT - - +e2fsck -fp $FS -- 1.8.3.1