]>
Commit | Line | Data |
---|---|---|
221ef3ca GKH |
1 | From 9a8fca62aacc1599fea8e813d01e1955513e4fad Mon Sep 17 00:00:00 2001 |
2 | From: Filipe Manana <fdmanana@suse.com> | |
3 | Date: Fri, 11 May 2018 16:42:42 +0100 | |
4 | Subject: Btrfs: fix xattr loss after power failure | |
5 | ||
6 | From: Filipe Manana <fdmanana@suse.com> | |
7 | ||
8 | commit 9a8fca62aacc1599fea8e813d01e1955513e4fad upstream. | |
9 | ||
10 | If a file has xattrs, we fsync it, to ensure we clear the flags | |
11 | BTRFS_INODE_NEEDS_FULL_SYNC and BTRFS_INODE_COPY_EVERYTHING from its | |
12 | inode, the current transaction commits and then we fsync it (without | |
13 | either of those bits being set in its inode), we end up not logging | |
14 | all its xattrs. This results in deleting all xattrs when replying the | |
15 | log after a power failure. | |
16 | ||
17 | Trivial reproducer | |
18 | ||
19 | $ mkfs.btrfs -f /dev/sdb | |
20 | $ mount /dev/sdb /mnt | |
21 | ||
22 | $ touch /mnt/foobar | |
23 | $ setfattr -n user.xa -v qwerty /mnt/foobar | |
24 | $ xfs_io -c "fsync" /mnt/foobar | |
25 | ||
26 | $ sync | |
27 | ||
28 | $ xfs_io -c "pwrite -S 0xab 0 64K" /mnt/foobar | |
29 | $ xfs_io -c "fsync" /mnt/foobar | |
30 | <power failure> | |
31 | ||
32 | $ mount /dev/sdb /mnt | |
33 | $ getfattr --absolute-names --dump /mnt/foobar | |
34 | <empty output> | |
35 | $ | |
36 | ||
37 | So fix this by making sure all xattrs are logged if we log a file's inode | |
38 | item and neither the flags BTRFS_INODE_NEEDS_FULL_SYNC nor | |
39 | BTRFS_INODE_COPY_EVERYTHING were set in the inode. | |
40 | ||
41 | Fixes: 36283bf777d9 ("Btrfs: fix fsync xattr loss in the fast fsync path") | |
42 | Cc: <stable@vger.kernel.org> # 4.2+ | |
43 | Signed-off-by: Filipe Manana <fdmanana@suse.com> | |
44 | Signed-off-by: David Sterba <dsterba@suse.com> | |
45 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
46 | ||
47 | --- | |
48 | fs/btrfs/tree-log.c | 7 +++++++ | |
49 | 1 file changed, 7 insertions(+) | |
50 | ||
51 | --- a/fs/btrfs/tree-log.c | |
52 | +++ b/fs/btrfs/tree-log.c | |
53 | @@ -4568,6 +4568,7 @@ static int btrfs_log_inode(struct btrfs_ | |
54 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | |
55 | u64 logged_isize = 0; | |
56 | bool need_log_inode_item = true; | |
57 | + bool xattrs_logged = false; | |
58 | ||
59 | path = btrfs_alloc_path(); | |
60 | if (!path) | |
61 | @@ -4808,6 +4809,7 @@ next_slot: | |
62 | err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path); | |
63 | if (err) | |
64 | goto out_unlock; | |
65 | + xattrs_logged = true; | |
66 | if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) { | |
67 | btrfs_release_path(path); | |
68 | btrfs_release_path(dst_path); | |
69 | @@ -4820,6 +4822,11 @@ log_extents: | |
70 | btrfs_release_path(dst_path); | |
71 | if (need_log_inode_item) { | |
72 | err = log_inode_item(trans, log, dst_path, inode); | |
73 | + if (!err && !xattrs_logged) { | |
74 | + err = btrfs_log_all_xattrs(trans, root, inode, path, | |
75 | + dst_path); | |
76 | + btrfs_release_path(path); | |
77 | + } | |
78 | if (err) | |
79 | goto out_unlock; | |
80 | } |