Commit 7aa6d359 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: do nofs allocations when adding and removing qgroup relations



When adding or removing a qgroup relation we are doing a GFP_KERNEL
allocation which is not safe because we are holding a transaction
handle open and that can make us deadlock if the allocator needs to
recurse into the filesystem. So just surround those calls with a
nofs context.

Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 3d05cad3
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/btrfs.h>
#include <linux/sched/mm.h>

#include "ctree.h"
#include "transaction.h"
@@ -1324,13 +1325,17 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
	struct btrfs_qgroup *member;
	struct btrfs_qgroup_list *list;
	struct ulist *tmp;
	unsigned int nofs_flag;
	int ret = 0;

	/* Check the level of src and dst first */
	if (btrfs_qgroup_level(src) >= btrfs_qgroup_level(dst))
		return -EINVAL;

	/* We hold a transaction handle open, must do a NOFS allocation. */
	nofs_flag = memalloc_nofs_save();
	tmp = ulist_alloc(GFP_KERNEL);
	memalloc_nofs_restore(nofs_flag);
	if (!tmp)
		return -ENOMEM;

@@ -1387,10 +1392,14 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
	struct btrfs_qgroup_list *list;
	struct ulist *tmp;
	bool found = false;
	unsigned int nofs_flag;
	int ret = 0;
	int ret2;

	/* We hold a transaction handle open, must do a NOFS allocation. */
	nofs_flag = memalloc_nofs_save();
	tmp = ulist_alloc(GFP_KERNEL);
	memalloc_nofs_restore(nofs_flag);
	if (!tmp)
		return -ENOMEM;