Sync ext4 encryption as of commit dffd334e4d7134
[ext4-patch-queue.git] / make-fsync-to-sync-parent-dir-in-no-journal-for-real-this-time
blob02d1f8b4f69ff776fcf5b2033356ca0785a97a86
1 ext4: make fsync to sync parent dir in no-journal for real this time
3 From: Lukas Czerner <lczerner@redhat.com>
5 Previously commit 14ece1028b3ed53ffec1b1213ffc6acaf79ad77c added a
6 support for for syncing parent directory of newly created inodes to
7 make sure that the inode is not lost after a power failure in
8 no-journal mode.
10 However this does not work in majority of cases, namely:
11  - if the directory has inline data
12  - if the directory is already indexed
13  - if the directory already has at least one block and:
14         - the new entry fits into it
15         - or we've successfully converted it to indexed
17 So in those cases we might lose the inode entirely even after fsync in
18 the no-journal mode. This also includes ext2 default mode obviously.
20 I've noticed this while running xfstest generic/321 and even though the
21 test should fail (we need to run fsck after a crash in no-journal mode)
22 I could not find a newly created entries even when if it was fsynced
23 before.
25 Fix this by adjusting the ext4_add_entry() successful exit paths to set
26 the inode EXT4_STATE_NEWENTRY so that fsync has the chance to fsync the
27 parent directory as well.
29 Signed-off-by: Lukas Czerner <lczerner@redhat.com>
30 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
31 Reviewed-by: Jan Kara <jack@suse.cz>
32 Cc: Frank Mayhar <fmayhar@google.com>
33 Cc: stable@vger.kernel.org
34 ---
35  fs/ext4/namei.c | 20 +++++++++++---------
36  1 file changed, 11 insertions(+), 9 deletions(-)
38 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
39 index efb64ae..23a0b9b 100644
40 --- a/fs/ext4/namei.c
41 +++ b/fs/ext4/namei.c
42 @@ -1864,7 +1864,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
43                           struct inode *inode)
44  {
45         struct inode *dir = dentry->d_parent->d_inode;
46 -       struct buffer_head *bh;
47 +       struct buffer_head *bh = NULL;
48         struct ext4_dir_entry_2 *de;
49         struct ext4_dir_entry_tail *t;
50         struct super_block *sb;
51 @@ -1888,14 +1888,14 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
52                         return retval;
53                 if (retval == 1) {
54                         retval = 0;
55 -                       return retval;
56 +                       goto out;
57                 }
58         }
60         if (is_dx(dir)) {
61                 retval = ext4_dx_add_entry(handle, dentry, inode);
62                 if (!retval || (retval != ERR_BAD_DX_DIR))
63 -                       return retval;
64 +                       goto out;
65                 ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
66                 dx_fallback++;
67                 ext4_mark_inode_dirty(handle, dir);
68 @@ -1907,14 +1907,15 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
69                         return PTR_ERR(bh);
71                 retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
72 -               if (retval != -ENOSPC) {
73 -                       brelse(bh);
74 -                       return retval;
75 -               }
76 +               if (retval != -ENOSPC)
77 +                       goto out;
79                 if (blocks == 1 && !dx_fallback &&
80 -                   EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
81 -                       return make_indexed_dir(handle, dentry, inode, bh);
82 +                   EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
83 +                       retval = make_indexed_dir(handle, dentry, inode, bh);
84 +                       bh = NULL; /* make_indexed_dir releases bh */
85 +                       goto out;
86 +               }
87                 brelse(bh);
88         }
89         bh = ext4_append(handle, dir, &block);
90 @@ -1930,6 +1931,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
91         }
93         retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
94 +out:
95         brelse(bh);
96         if (retval == 0)
97                 ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY);