add comment to fix-fencepost-error-in-ext4_update_other_inodes_time
[ext4-patch-queue.git] / reserve-hole-in-the-migration-to-non-extent-based-file
blob71d34f3387dd5ca35ccac290d783a695b0aef0bc
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
23   umount /mnt/ext4
24   e2fsck -nf /dev/sda6
25   ...
26   Inode 53, i_blocks is 16, should be 8.  Fix? no
27   ...
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
32 ---
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;
43         unsigned int                    i, len;
44 -       ext4_lblk_t                     end;
45 +       ext4_lblk_t                     start, end;
46         ext4_fsblk_t                    blk;
47         handle_t                        *handle;
48         int                             ret;
49 @@ -659,11 +659,12 @@ int ext4_ind_migrate(struct inode *inode)
50                 goto errout;
51         }
52         if (eh->eh_entries == 0)
53 -               blk = len = 0;
54 +               blk = len = start = end = 0;
55         else {
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) {
62                         ret = -EOPNOTSUPP;
63                         goto errout;
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);
72  errout:
73 -- 
74 1.8.3.1
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