1 ext4: correctly migrate a file with a hole at the beginning
3 From: Eryu Guan <guaneryu@gmail.com>
5 Currently ext4_ind_migrate() doesn't correctly handle a file which
6 contains a hole at the beginning of the file. This caused the migration
7 to be done incorrectly, and then if there is a subsequent following
8 delayed allocation write to the "hole", this would reclaim the same data
9 blocks again and results in fs corruption.
11 # assmuing 4k block size ext4, with delalloc enabled
12 # skip the first block and write to the second block
13 xfs_io -fc "pwrite 4k 4k" -c "fsync" /mnt/ext4/testfile
15 # converting to indirect-mapped file, which would move the data blocks
16 # to the beginning of the file, but extent status cache still marks
17 # that region as a hole
18 chattr -e /mnt/ext4/testfile
20 # delayed allocation writes to the "hole", reclaim the same data block
21 # again, results in i_blocks corruption
22 xfs_io -c "pwrite 0 4k" /mnt/ext4/testfile
26 Inode 53, i_blocks is 16, should be 8. Fix? no
29 Signed-off-by: Eryu Guan <guaneryu@gmail.com>
30 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
31 Cc: stable@vger.kernel.org
33 fs/ext4/migrate.c | 9 +++++----
34 1 file changed, 5 insertions(+), 4 deletions(-)
36 diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
37 index 3651141..10824b0 100644
38 --- a/fs/ext4/migrate.c
39 +++ b/fs/ext4/migrate.c
40 @@ -620,7 +620,7 @@ int ext4_ind_migrate(struct inode *inode)
41 struct ext4_inode_info *ei = EXT4_I(inode);
42 struct ext4_extent *ex;
45 + ext4_lblk_t start, end;
49 @@ -659,11 +659,12 @@ int ext4_ind_migrate(struct inode *inode)
52 if (eh->eh_entries == 0)
54 + blk = len = start = end = 0;
56 len = le16_to_cpu(ex->ee_len);
57 blk = ext4_ext_pblock(ex);
58 - end = le32_to_cpu(ex->ee_block) + len - 1;
59 + start = le32_to_cpu(ex->ee_block);
60 + end = start + len - 1;
61 if (end >= EXT4_NDIR_BLOCKS) {
64 @@ -672,7 +673,7 @@ int ext4_ind_migrate(struct inode *inode)
66 ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
67 memset(ei->i_data, 0, sizeof(ei->i_data));
68 - for (i=0; i < len; i++)
69 + for (i = start; i <= end; i++)
70 ei->i_data[i] = cpu_to_le32(blk++);
71 ext4_mark_inode_dirty(handle, inode);
77 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
78 the body of a message to majordomo@vger.kernel.org
79 More majordomo info at http://vger.kernel.org/majordomo-info.html