Skip to content

Commit 84da16e

Browse files
fdmananajfvogel
authored andcommitted
Btrfs: fix xattr loss after power failure
If a file has xattrs, we fsync it, to ensure we clear the flags BTRFS_INODE_NEEDS_FULL_SYNC and BTRFS_INODE_COPY_EVERYTHING from its inode, the current transaction commits and then we fsync it (without either of those bits being set in its inode), we end up not logging all its xattrs. This results in deleting all xattrs when replying the log after a power failure. Trivial reproducer $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ touch /mnt/foobar $ setfattr -n user.xa -v qwerty /mnt/foobar $ xfs_io -c "fsync" /mnt/foobar $ sync $ xfs_io -c "pwrite -S 0xab 0 64K" /mnt/foobar $ xfs_io -c "fsync" /mnt/foobar <power failure> $ mount /dev/sdb /mnt $ getfattr --absolute-names --dump /mnt/foobar <empty output> $ So fix this by making sure all xattrs are logged if we log a file's inode item and neither the flags BTRFS_INODE_NEEDS_FULL_SYNC nor BTRFS_INODE_COPY_EVERYTHING were set in the inode. Fixes: 36283bf ("Btrfs: fix fsync xattr loss in the fast fsync path") Cc: <[email protected]> # 4.2+ Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]> (cherry picked from commit 9a8fca6) Orabug: 28893942 Signed-off-by: Somasundaram Krishnasamy <[email protected]> Reviewed-by: Jack Vogel <[email protected]> Reviewed-by: Chuck Anderson <[email protected]>
1 parent 652faa3 commit 84da16e

File tree

1 file changed

+7
-0
lines changed

1 file changed

+7
-0
lines changed

fs/btrfs/tree-log.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4776,6 +4776,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
47764776
struct extent_map_tree *em_tree = &inode->extent_tree;
47774777
u64 logged_isize = 0;
47784778
bool need_log_inode_item = true;
4779+
bool xattrs_logged = false;
47794780

47804781
path = btrfs_alloc_path();
47814782
if (!path)
@@ -5078,6 +5079,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
50785079
err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path);
50795080
if (err)
50805081
goto out_unlock;
5082+
xattrs_logged = true;
50815083
if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) {
50825084
btrfs_release_path(path);
50835085
btrfs_release_path(dst_path);
@@ -5090,6 +5092,11 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
50905092
btrfs_release_path(dst_path);
50915093
if (need_log_inode_item) {
50925094
err = log_inode_item(trans, log, dst_path, inode);
5095+
if (!err && !xattrs_logged) {
5096+
err = btrfs_log_all_xattrs(trans, root, inode, path,
5097+
dst_path);
5098+
btrfs_release_path(path);
5099+
}
50935100
if (err)
50945101
goto out_unlock;
50955102
}

0 commit comments

Comments
 (0)