add patch fix-check-of-dqget-return-value-in-ext4_ioctl_setproject
[ext4-patch-queue.git] / fix-data-exposure-after-a-crash
blobfe7bbde209b9784becac2abac932ed8ef04e19d1
1 ext4: fix data exposure after a crash
3 From: Jan Kara <jack@suse.cz>
5 Huang has reported that in his powerfail testing he is seeing stale
6 block contents in some of recently allocated blocks although he mounts
7 ext4 in data=ordered mode. After some investigation I have found out
8 that indeed when delayed allocation is used, we don't add inode to
9 transaction's list of inodes needing flushing before commit. Originally
10 we were doing that but commit f3b59291a69d removed the logic with a
11 flawed argument that it is not needed.
13 The problem is that although for delayed allocated blocks we write their
14 contents immediately after allocating them, there is no guarantee that
15 the IO scheduler or device doesn't reorder things and thus transaction
16 allocating blocks and attaching them to inode can reach stable storage
17 before actual block contents. Actually whenever we attach freshly
18 allocated blocks to inode using a written extent, we should add inode to
19 transaction's ordered inode list to make sure we properly wait for block
20 contents to be written before committing the transaction. So that is
21 what we do in this patch. This also handles other cases where stale data
22 exposure was possible - like filling hole via mmap in
23 data=ordered,nodelalloc mode.
25 The only exception to the above rule are extending direct IO writes where
26 blkdev_direct_IO() waits for IO to complete before increasing i_size and
27 thus stale data exposure is not possible. For now we don't complicate
28 the code with optimizing this special case since the overhead is pretty
29 low. In case this is observed to be a performance problem we can always
30 handle it using a special flag to ext4_map_blocks().
32 CC: stable@vger.kernel.org
33 Fixes: f3b59291a69d0b734be1fc8be489fef2dd846d3d
34 Reported-by: "HUANG Weller (CM/ESW12-CN)" <Weller.Huang@cn.bosch.com>
35 Tested-by: "HUANG Weller (CM/ESW12-CN)" <Weller.Huang@cn.bosch.com>
36 Signed-off-by: Jan Kara <jack@suse.cz>
37 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
38 ---
39  fs/ext4/inode.c | 24 +++++++++++++++---------
40  1 file changed, 15 insertions(+), 9 deletions(-)
42 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
43 index 981a1fc..250c2df 100644
44 --- a/fs/ext4/inode.c
45 +++ b/fs/ext4/inode.c
46 @@ -684,6 +684,21 @@ out_sem:
47                 ret = check_block_validity(inode, map);
48                 if (ret != 0)
49                         return ret;
51 +               /*
52 +                * Inodes with freshly allocated blocks where contents will be
53 +                * visible after transaction commit must be on transaction's
54 +                * ordered data list.
55 +                */
56 +               if (map->m_flags & EXT4_MAP_NEW &&
57 +                   !(map->m_flags & EXT4_MAP_UNWRITTEN) &&
58 +                   !(flags & EXT4_GET_BLOCKS_ZERO) &&
59 +                   !IS_NOQUOTA(inode) &&
60 +                   ext4_should_order_data(inode)) {
61 +                       ret = ext4_jbd2_file_inode(handle, inode);
62 +                       if (ret)
63 +                               return ret;
64 +               }
65         }
66         return retval;
67  }
68 @@ -1289,15 +1304,6 @@ static int ext4_write_end(struct file *file,
69         int i_size_changed = 0;
71         trace_ext4_write_end(inode, pos, len, copied);
72 -       if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
73 -               ret = ext4_jbd2_file_inode(handle, inode);
74 -               if (ret) {
75 -                       unlock_page(page);
76 -                       put_page(page);
77 -                       goto errout;
78 -               }
79 -       }
81         if (ext4_has_inline_data(inode)) {
82                 ret = ext4_write_inline_data_end(inode, pos, len,
83                                                  copied, page);