]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.133/btrfs-fix-xattr-loss-after-power-failure.patch
Remove duplicated commits
[thirdparty/kernel/stable-queue.git] / releases / 4.4.133 / btrfs-fix-xattr-loss-after-power-failure.patch
CommitLineData
221ef3ca
GKH
1From 9a8fca62aacc1599fea8e813d01e1955513e4fad Mon Sep 17 00:00:00 2001
2From: Filipe Manana <fdmanana@suse.com>
3Date: Fri, 11 May 2018 16:42:42 +0100
4Subject: Btrfs: fix xattr loss after power failure
5
6From: Filipe Manana <fdmanana@suse.com>
7
8commit 9a8fca62aacc1599fea8e813d01e1955513e4fad upstream.
9
10If a file has xattrs, we fsync it, to ensure we clear the flags
11BTRFS_INODE_NEEDS_FULL_SYNC and BTRFS_INODE_COPY_EVERYTHING from its
12inode, the current transaction commits and then we fsync it (without
13either of those bits being set in its inode), we end up not logging
14all its xattrs. This results in deleting all xattrs when replying the
15log after a power failure.
16
17Trivial 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
37So fix this by making sure all xattrs are logged if we log a file's inode
38item and neither the flags BTRFS_INODE_NEEDS_FULL_SYNC nor
39BTRFS_INODE_COPY_EVERYTHING were set in the inode.
40
41Fixes: 36283bf777d9 ("Btrfs: fix fsync xattr loss in the fast fsync path")
42Cc: <stable@vger.kernel.org> # 4.2+
43Signed-off-by: Filipe Manana <fdmanana@suse.com>
44Signed-off-by: David Sterba <dsterba@suse.com>
45Signed-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 }