]>
Commit | Line | Data |
---|---|---|
14e9555d GKH |
1 | From 5338e43abbab13791144d37fd8846847062351c6 Mon Sep 17 00:00:00 2001 |
2 | From: Filipe Manana <fdmanana@suse.com> | |
3 | Date: Wed, 15 May 2019 16:02:47 +0100 | |
4 | Subject: Btrfs: fix wrong ctime and mtime of a directory after log replay | |
5 | ||
6 | From: Filipe Manana <fdmanana@suse.com> | |
7 | ||
8 | commit 5338e43abbab13791144d37fd8846847062351c6 upstream. | |
9 | ||
10 | When replaying a log that contains a new file or directory name that needs | |
11 | to be added to its parent directory, we end up updating the mtime and the | |
12 | ctime of the parent directory to the current time after we have set their | |
13 | values to the correct ones (set at fsync time), efectivelly losing them. | |
14 | ||
15 | Sample reproducer: | |
16 | ||
17 | $ mkfs.btrfs -f /dev/sdb | |
18 | $ mount /dev/sdb /mnt | |
19 | ||
20 | $ mkdir /mnt/dir | |
21 | $ touch /mnt/dir/file | |
22 | ||
23 | # fsync of the directory is optional, not needed | |
24 | $ xfs_io -c fsync /mnt/dir | |
25 | $ xfs_io -c fsync /mnt/dir/file | |
26 | ||
27 | $ stat -c %Y /mnt/dir | |
28 | 1557856079 | |
29 | ||
30 | <power failure> | |
31 | ||
32 | $ sleep 3 | |
33 | $ mount /dev/sdb /mnt | |
34 | $ stat -c %Y /mnt/dir | |
35 | 1557856082 | |
36 | ||
37 | --> should have been 1557856079, the mtime is updated to the current | |
38 | time when replaying the log | |
39 | ||
40 | Fix this by not updating the mtime and ctime to the current time at | |
41 | btrfs_add_link() when we are replaying a log tree. | |
42 | ||
43 | This could be triggered by my recent fsync fuzz tester for fstests, for | |
44 | which an fstests patch exists titled "fstests: generic, fsync fuzz tester | |
45 | with fsstress". | |
46 | ||
47 | Fixes: e02119d5a7b43 ("Btrfs: Add a write ahead tree log to optimize synchronous operations") | |
48 | CC: stable@vger.kernel.org # 4.4+ | |
49 | Reviewed-by: Nikolay Borisov <nborisov@suse.com> | |
50 | Signed-off-by: Filipe Manana <fdmanana@suse.com> | |
51 | Signed-off-by: David Sterba <dsterba@suse.com> | |
52 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
53 | ||
54 | --- | |
55 | fs/btrfs/inode.c | 14 ++++++++++++-- | |
56 | 1 file changed, 12 insertions(+), 2 deletions(-) | |
57 | ||
58 | --- a/fs/btrfs/inode.c | |
59 | +++ b/fs/btrfs/inode.c | |
60 | @@ -6426,8 +6426,18 @@ int btrfs_add_link(struct btrfs_trans_ha | |
61 | btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size + | |
62 | name_len * 2); | |
63 | inode_inc_iversion(&parent_inode->vfs_inode); | |
64 | - parent_inode->vfs_inode.i_mtime = parent_inode->vfs_inode.i_ctime = | |
65 | - current_time(&parent_inode->vfs_inode); | |
66 | + /* | |
67 | + * If we are replaying a log tree, we do not want to update the mtime | |
68 | + * and ctime of the parent directory with the current time, since the | |
69 | + * log replay procedure is responsible for setting them to their correct | |
70 | + * values (the ones it had when the fsync was done). | |
71 | + */ | |
72 | + if (!test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags)) { | |
73 | + struct timespec64 now = current_time(&parent_inode->vfs_inode); | |
74 | + | |
75 | + parent_inode->vfs_inode.i_mtime = now; | |
76 | + parent_inode->vfs_inode.i_ctime = now; | |
77 | + } | |
78 | ret = btrfs_update_inode(trans, root, &parent_inode->vfs_inode); | |
79 | if (ret) | |
80 | btrfs_abort_transaction(trans, ret); |