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
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
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
35 fs/ext4/namei.c | 19 ++++++++++---------
36 1 file changed, 10 insertions(+), 9 deletions(-)
38 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
39 index 2291923..25e1e03 100644
42 @@ -1865,7 +1865,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
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 @@ -1889,14 +1889,14 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
61 retval = ext4_dx_add_entry(handle, dentry, inode);
62 if (!retval || (retval != ERR_BAD_DX_DIR))
65 ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
67 ext4_mark_inode_dirty(handle, dir);
68 @@ -1908,14 +1908,14 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
71 retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
72 - if (retval != -ENOSPC) {
76 + if (retval != -ENOSPC)
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);
88 bh = ext4_append(handle, dir, &block);
89 @@ -1931,6 +1931,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
92 retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
96 ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY);
101 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
102 the body of a message to majordomo@vger.kernel.org
103 More majordomo info at http://vger.kernel.org/majordomo-info.html