The allocation happens with GFP_KERNEL after a transaction has been
started, this can potentially cause deadlock if reclaim tries to get the
memory by flushing filesystem data.

The qgroup_ulist is not used during transaction start as the quotas are
not yet enabled but to provide the same semantics, use a temporary
variable and assign fs_info::qgroup_ulist as before.

Signed-off-by: David Sterba <[email protected]>
---
 fs/btrfs/qgroup.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index c1cd5558a646..9e49d5e132b8 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -887,6 +887,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
        struct btrfs_key found_key;
        struct btrfs_qgroup *qgroup = NULL;
        struct btrfs_trans_handle *trans = NULL;
+       struct ulist *tmp_ulist;
        int ret = 0;
        int slot;
 
@@ -894,6 +895,12 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
        if (fs_info->quota_root)
                goto out;
 
+       tmp_ulist = ulist_alloc(GFP_KERNEL);
+       if (!tmp_ulist) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
        /*
         * 1 for quota root item
         * 1 for BTRFS_QGROUP_STATUS item
@@ -909,12 +916,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
                goto out;
        }
 
-       fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
-       if (!fs_info->qgroup_ulist) {
-               ret = -ENOMEM;
-               btrfs_abort_transaction(trans, ret);
-               goto out;
-       }
+       fs_info->qgroup_ulist = tmp_ulist;
 
        /*
         * initially create the quota tree
-- 
2.20.1

Reply via email to