]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.14/btrfs-fix-fsync-not-persisting-changed-attributes-of-a-directory.patch
Linux 4.19.49
[thirdparty/kernel/stable-queue.git] / queue-4.14 / btrfs-fix-fsync-not-persisting-changed-attributes-of-a-directory.patch
1 From 60d9f50308e5df19bc18c2fefab0eba4a843900a Mon Sep 17 00:00:00 2001
2 From: Filipe Manana <fdmanana@suse.com>
3 Date: Thu, 16 May 2019 15:48:55 +0100
4 Subject: Btrfs: fix fsync not persisting changed attributes of a directory
5
6 From: Filipe Manana <fdmanana@suse.com>
7
8 commit 60d9f50308e5df19bc18c2fefab0eba4a843900a upstream.
9
10 While logging an inode we follow its ancestors and for each one we mark
11 it as logged in the current transaction, even if we have not logged it.
12 As a consequence if we change an attribute of an ancestor, such as the
13 UID or GID for example, and then explicitly fsync it, we end up not
14 logging the inode at all despite returning success to user space, which
15 results in the attribute being lost if a power failure happens after
16 the fsync.
17
18 Sample reproducer:
19
20 $ mkfs.btrfs -f /dev/sdb
21 $ mount /dev/sdb /mnt
22
23 $ mkdir /mnt/dir
24 $ chown 6007:6007 /mnt/dir
25
26 $ sync
27
28 $ chown 9003:9003 /mnt/dir
29 $ touch /mnt/dir/file
30 $ xfs_io -c fsync /mnt/dir/file
31
32 # fsync our directory after fsync'ing the new file, should persist the
33 # new values for the uid and gid.
34 $ xfs_io -c fsync /mnt/dir
35
36 <power failure>
37
38 $ mount /dev/sdb /mnt
39 $ stat -c %u:%g /mnt/dir
40 6007:6007
41
42 --> should be 9003:9003, the uid and gid were not persisted, despite
43 the explicit fsync on the directory prior to the power failure
44
45 Fix this by not updating the logged_trans field of ancestor inodes when
46 logging an inode, since we have not logged them. Let only future calls to
47 btrfs_log_inode() to mark inodes as logged.
48
49 This could be triggered by my recent fsync fuzz tester for fstests, for
50 which an fstests patch exists titled "fstests: generic, fsync fuzz tester
51 with fsstress".
52
53 Fixes: 12fcfd22fe5b ("Btrfs: tree logging unlink/rename fixes")
54 CC: stable@vger.kernel.org # 4.4+
55 Signed-off-by: Filipe Manana <fdmanana@suse.com>
56 Signed-off-by: David Sterba <dsterba@suse.com>
57 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
58
59 ---
60 fs/btrfs/tree-log.c | 12 ------------
61 1 file changed, 12 deletions(-)
62
63 --- a/fs/btrfs/tree-log.c
64 +++ b/fs/btrfs/tree-log.c
65 @@ -5332,7 +5332,6 @@ static noinline int check_parent_dirs_fo
66 {
67 int ret = 0;
68 struct dentry *old_parent = NULL;
69 - struct btrfs_inode *orig_inode = inode;
70
71 /*
72 * for regular files, if its inode is already on disk, we don't
73 @@ -5352,16 +5351,6 @@ static noinline int check_parent_dirs_fo
74 }
75
76 while (1) {
77 - /*
78 - * If we are logging a directory then we start with our inode,
79 - * not our parent's inode, so we need to skip setting the
80 - * logged_trans so that further down in the log code we don't
81 - * think this inode has already been logged.
82 - */
83 - if (inode != orig_inode)
84 - inode->logged_trans = trans->transid;
85 - smp_mb();
86 -
87 if (btrfs_must_commit_transaction(trans, inode)) {
88 ret = 1;
89 break;
90 @@ -6091,7 +6080,6 @@ void btrfs_record_unlink_dir(struct btrf
91 * if this directory was already logged any new
92 * names for this file/dir will get recorded
93 */
94 - smp_mb();
95 if (dir->logged_trans == trans->transid)
96 return;
97