mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 05:34:13 +08:00
btrfs: fix race between quota disable and relocation
If we disable quotas while we have a relocation of a metadata block group
that has extents belonging to the quota root, we can cause the relocation
to fail with -ENOENT. This is because relocation builds backref nodes for
extents of the quota root and later needs to walk the backrefs and access
the quota root - however if in between a task disables quotas, it results
in deleting the quota root from the root tree (with btrfs_del_root(),
called from btrfs_quota_disable().
This can be sporadically triggered by test case btrfs/255 from fstests:
$ ./check btrfs/255
FSTYP -- btrfs
PLATFORM -- Linux/x86_64 debian0 6.4.0-rc6-btrfs-next-134+ #1 SMP PREEMPT_DYNAMIC Thu Jun 15 11:59:28 WEST 2023
MKFS_OPTIONS -- /dev/sdc
MOUNT_OPTIONS -- /dev/sdc /home/fdmanana/btrfs-tests/scratch_1
btrfs/255 6s ... _check_dmesg: something found in dmesg (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.dmesg)
- output mismatch (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad)
--- tests/btrfs/255.out 2023-03-02 21:47:53.876609426 +0000
+++ /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad 2023-06-16 10:20:39.267563212 +0100
@@ -1,2 +1,4 @@
QA output created by 255
+ERROR: error during balancing '/home/fdmanana/btrfs-tests/scratch_1': No such file or directory
+There may be more info in syslog - try dmesg | tail
Silence is golden
...
(Run 'diff -u /home/fdmanana/git/hub/xfstests/tests/btrfs/255.out /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad' to see the entire diff)
Ran: btrfs/255
Failures: btrfs/255
Failed 1 of 1 tests
To fix this make the quota disable operation take the cleaner mutex, as
relocation of a block group also takes this mutex. This is also what we
do when deleting a subvolume/snapshot, we take the cleaner mutex in the
cleaner kthread (at cleaner_kthread()) and then we call btrfs_del_root()
at btrfs_drop_snapshot() while under the protection of the cleaner mutex.
Fixes: bed92eae26
("Btrfs: qgroup implementation and prototypes")
CC: stable@vger.kernel.org # 5.4+
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
08eb2ad9db
commit
8a4a0b2a3e
@ -1232,12 +1232,23 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* We need to have subvol_sem write locked, to prevent races between
|
||||
* concurrent tasks trying to disable quotas, because we will unlock
|
||||
* and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
|
||||
* We need to have subvol_sem write locked to prevent races with
|
||||
* snapshot creation.
|
||||
*/
|
||||
lockdep_assert_held_write(&fs_info->subvol_sem);
|
||||
|
||||
/*
|
||||
* Lock the cleaner mutex to prevent races with concurrent relocation,
|
||||
* because relocation may be building backrefs for blocks of the quota
|
||||
* root while we are deleting the root. This is like dropping fs roots
|
||||
* of deleted snapshots/subvolumes, we need the same protection.
|
||||
*
|
||||
* This also prevents races between concurrent tasks trying to disable
|
||||
* quotas, because we will unlock and relock qgroup_ioctl_lock across
|
||||
* BTRFS_FS_QUOTA_ENABLED changes.
|
||||
*/
|
||||
mutex_lock(&fs_info->cleaner_mutex);
|
||||
|
||||
mutex_lock(&fs_info->qgroup_ioctl_lock);
|
||||
if (!fs_info->quota_root)
|
||||
goto out;
|
||||
@ -1319,6 +1330,7 @@ out:
|
||||
btrfs_end_transaction(trans);
|
||||
else if (trans)
|
||||
ret = btrfs_end_transaction(trans);
|
||||
mutex_unlock(&fs_info->cleaner_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user