Home Home > GIT Browse > stable
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2019-01-18 07:53:27 +0100
committerJiri Slaby <jslaby@suse.cz>2019-01-18 07:53:43 +0100
commitfd714bcea58e3fe31b19824b70511f183424fcea (patch)
tree216b5142a9825adb628f5cd02fa97c0547ce9cfd
parent6ae5bfac0a05746958c3fab3b2162e7340225abb (diff)
Btrfs: fix deadlock when enabling quotas due to concurrent
snapshot creation (bnc#1012628).
-rw-r--r--patches.kernel.org/4.20.3-056-Btrfs-fix-deadlock-when-enabling-quotas-due-to.patch138
-rw-r--r--series.conf1
2 files changed, 139 insertions, 0 deletions
diff --git a/patches.kernel.org/4.20.3-056-Btrfs-fix-deadlock-when-enabling-quotas-due-to.patch b/patches.kernel.org/4.20.3-056-Btrfs-fix-deadlock-when-enabling-quotas-due-to.patch
new file mode 100644
index 0000000000..6ab374b51a
--- /dev/null
+++ b/patches.kernel.org/4.20.3-056-Btrfs-fix-deadlock-when-enabling-quotas-due-to.patch
@@ -0,0 +1,138 @@
+From: Filipe Manana <fdmanana@suse.com>
+Date: Mon, 19 Nov 2018 14:15:36 +0000
+Subject: [PATCH] Btrfs: fix deadlock when enabling quotas due to concurrent
+ snapshot creation
+References: bnc#1012628
+Patch-mainline: 4.20.3
+Git-commit: 9a6f209e36500efac51528132a3e3083586eda5f
+
+commit 9a6f209e36500efac51528132a3e3083586eda5f upstream.
+
+If the quota enable and snapshot creation ioctls are called concurrently
+we can get into a deadlock where the task enabling quotas will deadlock
+on the fs_info->qgroup_ioctl_lock mutex because it attempts to lock it
+twice, or the task creating a snapshot tries to commit the transaction
+while the task enabling quota waits for the former task to commit the
+transaction while holding the mutex. The following time diagrams show how
+both cases happen.
+
+First scenario:
+
+ CPU 0 CPU 1
+
+ btrfs_ioctl()
+ btrfs_ioctl_quota_ctl()
+ btrfs_quota_enable()
+ mutex_lock(fs_info->qgroup_ioctl_lock)
+ btrfs_start_transaction()
+
+ btrfs_ioctl()
+ btrfs_ioctl_snap_create_v2
+ create_snapshot()
+ --> adds snapshot to the
+ list pending_snapshots
+ of the current
+ transaction
+
+ btrfs_commit_transaction()
+ create_pending_snapshots()
+ create_pending_snapshot()
+ qgroup_account_snapshot()
+ btrfs_qgroup_inherit()
+ mutex_lock(fs_info->qgroup_ioctl_lock)
+ --> deadlock, mutex already locked
+ by this task at
+ btrfs_quota_enable()
+
+Second scenario:
+
+ CPU 0 CPU 1
+
+ btrfs_ioctl()
+ btrfs_ioctl_quota_ctl()
+ btrfs_quota_enable()
+ mutex_lock(fs_info->qgroup_ioctl_lock)
+ btrfs_start_transaction()
+
+ btrfs_ioctl()
+ btrfs_ioctl_snap_create_v2
+ create_snapshot()
+ --> adds snapshot to the
+ list pending_snapshots
+ of the current
+ transaction
+
+ btrfs_commit_transaction()
+ --> waits for task at
+ CPU 0 to release
+ its transaction
+ handle
+
+ btrfs_commit_transaction()
+ --> sees another task started
+ the transaction commit first
+ --> releases its transaction
+ handle
+ --> waits for the transaction
+ commit to be completed by
+ the task at CPU 1
+
+ create_pending_snapshot()
+ qgroup_account_snapshot()
+ btrfs_qgroup_inherit()
+ mutex_lock(fs_info->qgroup_ioctl_lock)
+ --> deadlock, task at CPU 0
+ has the mutex locked but
+ it is waiting for us to
+ finish the transaction
+ commit
+
+So fix this by setting the quota enabled flag in fs_info after committing
+the transaction at btrfs_quota_enable(). This ends up serializing quota
+enable and snapshot creation as if the snapshot creation happened just
+before the quota enable request. The quota rescan task, scheduled after
+committing the transaction in btrfs_quote_enable(), will do the accounting.
+
+Fixes: 6426c7ad697d ("btrfs: qgroup: Fix qgroup accounting when creating snapshot")
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ fs/btrfs/qgroup.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index f70825af6438..9e419f6878c5 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1013,16 +1013,22 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
+ btrfs_abort_transaction(trans, ret);
+ goto out_free_path;
+ }
+- spin_lock(&fs_info->qgroup_lock);
+- fs_info->quota_root = quota_root;
+- set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+- spin_unlock(&fs_info->qgroup_lock);
+
+ ret = btrfs_commit_transaction(trans);
+ trans = NULL;
+ if (ret)
+ goto out_free_path;
+
++ /*
++ * Set quota enabled flag after committing the transaction, to avoid
++ * deadlocks on fs_info->qgroup_ioctl_lock with concurrent snapshot
++ * creation.
++ */
++ spin_lock(&fs_info->qgroup_lock);
++ fs_info->quota_root = quota_root;
++ set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
++ spin_unlock(&fs_info->qgroup_lock);
++
+ ret = qgroup_rescan_init(fs_info, 0, 1);
+ if (!ret) {
+ qgroup_rescan_zero_tracking(fs_info);
+--
+2.20.1
+
diff --git a/series.conf b/series.conf
index d5cded3ef8..b9ce242ffb 100644
--- a/series.conf
+++ b/series.conf
@@ -293,6 +293,7 @@
patches.kernel.org/4.20.3-053-mm-page_mapped-don-t-assume-compound-page-is-h.patch
patches.kernel.org/4.20.3-054-sunrpc-use-after-free-in-svc_process_common.patch
patches.kernel.org/4.20.3-055-Btrfs-fix-access-to-available-allocation-bits-.patch
+ patches.kernel.org/4.20.3-056-Btrfs-fix-deadlock-when-enabling-quotas-due-to.patch
########################################################
# Build fixes that apply to the vanilla kernel too.