1 ext4: be more strict when migrating to non-extent based file
3 From: Eryu Guan <guaneryu@gmail.com>
5 Currently the check in ext4_ind_migrate() is not enough before doing the
8 a) delayed allocated extents could bypass the check on eh->eh_entries
11 This can be demonstrated by this script
13 xfs_io -fc "pwrite 0 4k" -c "pwrite 8k 4k" /mnt/ext4/testfile
14 chattr -e /mnt/ext4/testfile
16 where testfile has two extents but still be converted to non-extent
19 b) only extent length is checked but not the offset, which would result
20 in data lose (delalloc) or fs corruption (nodelalloc), because
21 non-extent based file only supports at most (12 + 2^10 + 2^20 + 2^30)
24 This can be demostrated by
26 xfs_io -fc "pwrite 5T 4k" /mnt/ext4/testfile
27 chattr -e /mnt/ext4/testfile
30 If delalloc is enabled, dmesg prints
31 EXT4-fs warning (device dm-4): ext4_block_to_path:105: block 1342177280 > max in inode 53
32 EXT4-fs (dm-4): Delayed block allocation failed for inode 53 at logical offset 1342177280 with max blocks 1 with error 5
33 EXT4-fs (dm-4): This should not happen!! Data will be lost
35 If delalloc is disabled, e2fsck -nf shows corruption
36 Inode 53, i_size is 5497558142976, should be 4096. Fix? no
40 a) forcing all delayed allocation blocks to be allocated before checking
41 eh->eh_depth and eh->eh_entries
42 b) limiting the last logical block of the extent is within direct map
44 Signed-off-by: Eryu Guan <guaneryu@gmail.com>
45 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
46 Cc: stable@vger.kernel.org
48 fs/ext4/migrate.c | 12 +++++++++++-
49 1 file changed, 11 insertions(+), 1 deletion(-)
51 diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
52 index b52374e..3651141 100644
53 --- a/fs/ext4/migrate.c
54 +++ b/fs/ext4/migrate.c
55 @@ -620,6 +620,7 @@ int ext4_ind_migrate(struct inode *inode)
56 struct ext4_inode_info *ei = EXT4_I(inode);
57 struct ext4_extent *ex;
63 @@ -633,6 +634,14 @@ int ext4_ind_migrate(struct inode *inode)
64 EXT4_FEATURE_RO_COMPAT_BIGALLOC))
68 + * In order to get correct extent info, force all delayed allocation
69 + * blocks to be allocated, otherwise delayed allocation blocks may not
70 + * be reflected and bypass the checks on extent header.
72 + if (test_opt(inode->i_sb, DELALLOC))
73 + ext4_alloc_da_blocks(inode);
75 handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
77 return PTR_ERR(handle);
78 @@ -654,7 +663,8 @@ int ext4_ind_migrate(struct inode *inode)
80 len = le16_to_cpu(ex->ee_len);
81 blk = ext4_ext_pblock(ex);
82 - if (len > EXT4_NDIR_BLOCKS) {
83 + end = le32_to_cpu(ex->ee_block) + len - 1;
84 + if (end >= EXT4_NDIR_BLOCKS) {
92 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
93 the body of a message to majordomo@vger.kernel.org
94 More majordomo info at http://vger.kernel.org/majordomo-info.html