aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2015-04-03 10:46:58 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-04-03 10:46:58 -0400
commite12fb97222fc41e8442896934f76d39ef99b590a (patch)
tree5325c812dee98b42b4e5bdc7e3f3e827d024f5b9 /fs
parent9d21c9fa2cc24e2a195a79c27b6550e1a96051a4 (diff)
ext4: make fsync to sync parent dir in no-journal for real this time
Previously commit 14ece1028b3ed53ffec1b1213ffc6acaf79ad77c added a support for for syncing parent directory of newly created inodes to make sure that the inode is not lost after a power failure in no-journal mode. However this does not work in majority of cases, namely: - if the directory has inline data - if the directory is already indexed - if the directory already has at least one block and: - the new entry fits into it - or we've successfully converted it to indexed So in those cases we might lose the inode entirely even after fsync in the no-journal mode. This also includes ext2 default mode obviously. I've noticed this while running xfstest generic/321 and even though the test should fail (we need to run fsck after a crash in no-journal mode) I could not find a newly created entries even when if it was fsynced before. Fix this by adjusting the ext4_add_entry() successful exit paths to set the inode EXT4_STATE_NEWENTRY so that fsync has the chance to fsync the parent directory as well. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz> Cc: Frank Mayhar <fmayhar@google.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/namei.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index efb64aee5b9e..23a0b9bf822d 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1864,7 +1864,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
1864 struct inode *inode) 1864 struct inode *inode)
1865{ 1865{
1866 struct inode *dir = dentry->d_parent->d_inode; 1866 struct inode *dir = dentry->d_parent->d_inode;
1867 struct buffer_head *bh; 1867 struct buffer_head *bh = NULL;
1868 struct ext4_dir_entry_2 *de; 1868 struct ext4_dir_entry_2 *de;
1869 struct ext4_dir_entry_tail *t; 1869 struct ext4_dir_entry_tail *t;
1870 struct super_block *sb; 1870 struct super_block *sb;
@@ -1888,14 +1888,14 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
1888 return retval; 1888 return retval;
1889 if (retval == 1) { 1889 if (retval == 1) {
1890 retval = 0; 1890 retval = 0;
1891 return retval; 1891 goto out;
1892 } 1892 }
1893 } 1893 }
1894 1894
1895 if (is_dx(dir)) { 1895 if (is_dx(dir)) {
1896 retval = ext4_dx_add_entry(handle, dentry, inode); 1896 retval = ext4_dx_add_entry(handle, dentry, inode);
1897 if (!retval || (retval != ERR_BAD_DX_DIR)) 1897 if (!retval || (retval != ERR_BAD_DX_DIR))
1898 return retval; 1898 goto out;
1899 ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); 1899 ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
1900 dx_fallback++; 1900 dx_fallback++;
1901 ext4_mark_inode_dirty(handle, dir); 1901 ext4_mark_inode_dirty(handle, dir);
@@ -1907,14 +1907,15 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
1907 return PTR_ERR(bh); 1907 return PTR_ERR(bh);
1908 1908
1909 retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); 1909 retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
1910 if (retval != -ENOSPC) { 1910 if (retval != -ENOSPC)
1911 brelse(bh); 1911 goto out;
1912 return retval;
1913 }
1914 1912
1915 if (blocks == 1 && !dx_fallback && 1913 if (blocks == 1 && !dx_fallback &&
1916 EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) 1914 EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
1917 return make_indexed_dir(handle, dentry, inode, bh); 1915 retval = make_indexed_dir(handle, dentry, inode, bh);
1916 bh = NULL; /* make_indexed_dir releases bh */
1917 goto out;
1918 }
1918 brelse(bh); 1919 brelse(bh);
1919 } 1920 }
1920 bh = ext4_append(handle, dir, &block); 1921 bh = ext4_append(handle, dir, &block);
@@ -1930,6 +1931,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
1930 } 1931 }
1931 1932
1932 retval = add_dirent_to_buf(handle, dentry, inode, de, bh); 1933 retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
1934out:
1933 brelse(bh); 1935 brelse(bh);
1934 if (retval == 0) 1936 if (retval == 0)
1935 ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY); 1937 ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY);