public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item()
  2022-11-15 17:17 ` [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
@ 2022-11-15 16:22   ` ChenXiaoSong
  2022-11-15 22:50   ` Qu Wenruo
  1 sibling, 0 replies; 13+ messages in thread
From: ChenXiaoSong @ 2022-11-15 16:22 UTC (permalink / raw)
  To: clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, zhangxiaoxu5, yanaijie, quwenruo.btrfs,
	wqu

在 2022/11/16 1:17, ChenXiaoSong 写道:
> @@ -2987,6 +2986,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
>   		dstgroup->max_excl = srcgroup->max_excl;
>   		dstgroup->rsv_rfer = srcgroup->rsv_rfer;
>   		dstgroup->rsv_excl = srcgroup->rsv_excl;
> +		update_limit = false;
>   
>   		qgroup_dirty(fs_info, dstgroup);
>   		qgroup_dirty(fs_info, srcgroup);

No need to call update_qgroup_limit_item() when condition "if (srcid)" 
is true according to Qu Wenruo's suggestions, btrfs_run_qgroups() will 
update the quota tree to reflect the result after calling qgroup_dirty().

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 0/3] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item()
@ 2022-11-15 17:17 ChenXiaoSong
  2022-11-15 17:17 ` [PATCH v4 1/3] btrfs: add might_sleep() to some places " ChenXiaoSong
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: ChenXiaoSong @ 2022-11-15 17:17 UTC (permalink / raw)
  To: clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, chenxiaosong2, zhangxiaoxu5, yanaijie,
	quwenruo.btrfs, wqu

At least 3 places might sleep in update_qgroup_limit_item(), as shown below:

  update_qgroup_limit_item
    btrfs_alloc_path
      /* allocate memory non-atomically, might sleep */
      kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS)
    btrfs_search_slot
      setup_nodes_for_search
        reada_for_balance
          btrfs_readahead_node_child
            btrfs_readahead_tree_block
              btrfs_find_create_tree_block
                alloc_extent_buffer
                  kmem_cache_zalloc
                    /* allocate memory non-atomically, might sleep */
                    kmem_cache_alloc(GFP_NOFS|__GFP_NOFAIL|__GFP_ZERO)
              read_extent_buffer_pages
                submit_extent_page
                  /* disk IO, might sleep */
                  submit_one_bio

Fix this by delaying the limit item updates until unlock the spin lock.

By the way, add might_sleep() to some places.

ChenXiaoSong (3):
  btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  btrfs: qgroup: introduce btrfs_update_quoto_limit() helper
  btrfs: qgroup: fix sleep from invalid context bug in
    update_qgroup_limit_item()

 fs/btrfs/ctree.c  |  2 ++
 fs/btrfs/qgroup.c | 45 ++++++++++++++++++++++++++-------------------
 2 files changed, 28 insertions(+), 19 deletions(-)

-- 
2.31.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-15 17:17 [PATCH v4 0/3] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
@ 2022-11-15 17:17 ` ChenXiaoSong
  2022-11-15 17:41   ` David Sterba
  2022-11-15 22:48   ` Qu Wenruo
  2022-11-15 17:17 ` [PATCH v4 2/3] btrfs: qgroup: introduce btrfs_update_quoto_limit() helper ChenXiaoSong
  2022-11-15 17:17 ` [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
  2 siblings, 2 replies; 13+ messages in thread
From: ChenXiaoSong @ 2022-11-15 17:17 UTC (permalink / raw)
  To: clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, chenxiaosong2, zhangxiaoxu5, yanaijie,
	quwenruo.btrfs, wqu

As the potential sleeping under spin lock is hard to spot, we should add
might_sleep() to some places.

Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
---
 fs/btrfs/ctree.c  | 2 ++
 fs/btrfs/qgroup.c | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index a9543f01184c..809053e9cfde 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1934,6 +1934,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	int min_write_lock_level;
 	int prev_cmp;
 
+	might_sleep();
+
 	lowest_level = p->lowest_level;
 	WARN_ON(lowest_level && ins_len > 0);
 	WARN_ON(p->nodes[0] != NULL);
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 9334c3157c22..d0480b9c6c86 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -779,6 +779,8 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 	int ret;
 	int slot;
 
+	might_sleep();
+
 	key.objectid = 0;
 	key.type = BTRFS_QGROUP_LIMIT_KEY;
 	key.offset = qgroup->qgroupid;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 2/3] btrfs: qgroup: introduce btrfs_update_quoto_limit() helper
  2022-11-15 17:17 [PATCH v4 0/3] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
  2022-11-15 17:17 ` [PATCH v4 1/3] btrfs: add might_sleep() to some places " ChenXiaoSong
@ 2022-11-15 17:17 ` ChenXiaoSong
  2022-11-15 17:33   ` David Sterba
  2022-11-15 17:17 ` [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
  2 siblings, 1 reply; 13+ messages in thread
From: ChenXiaoSong @ 2022-11-15 17:17 UTC (permalink / raw)
  To: clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, chenxiaosong2, zhangxiaoxu5, yanaijie,
	quwenruo.btrfs, wqu

No functional changed. Just simplify the code.

Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
---
 fs/btrfs/qgroup.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index d0480b9c6c86..ca609a70d067 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1677,6 +1677,19 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
 	return ret;
 }
 
+static int btrfs_update_quoto_limit(struct btrfs_trans_handle *trans,
+				    struct btrfs_qgroup *qgroup,
+				    struct btrfs_fs_info *fs_info)
+{
+	int ret = update_qgroup_limit_item(trans, qgroup);
+	if (ret) {
+		qgroup_mark_inconsistent(fs_info);
+		btrfs_info(fs_info, "unable to update quota limit for %llu",
+			   qgroup->qgroupid);
+	}
+	return ret;
+}
+
 int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid,
 		       struct btrfs_qgroup_limit *limit)
 {
@@ -1742,13 +1755,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid,
 
 	spin_unlock(&fs_info->qgroup_lock);
 
-	ret = update_qgroup_limit_item(trans, qgroup);
-	if (ret) {
-		qgroup_mark_inconsistent(fs_info);
-		btrfs_info(fs_info, "unable to update quota limit for %llu",
-		       qgroupid);
-	}
-
+	ret = btrfs_update_quoto_limit(trans, qgroup, fs_info);
 out:
 	mutex_unlock(&fs_info->qgroup_ioctl_lock);
 	return ret;
@@ -2824,9 +2831,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
 		ret = update_qgroup_info_item(trans, qgroup);
 		if (ret)
 			qgroup_mark_inconsistent(fs_info);
-		ret = update_qgroup_limit_item(trans, qgroup);
-		if (ret)
-			qgroup_mark_inconsistent(fs_info);
+		ret = btrfs_update_quoto_limit(trans, qgroup, fs_info);
 		spin_lock(&fs_info->qgroup_lock);
 	}
 	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
@@ -2953,14 +2958,9 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 		dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
 		dstgroup->rsv_excl = inherit->lim.rsv_excl;
 
-		ret = update_qgroup_limit_item(trans, dstgroup);
-		if (ret) {
-			qgroup_mark_inconsistent(fs_info);
-			btrfs_info(fs_info,
-				   "unable to update quota limit for %llu",
-				   dstgroup->qgroupid);
+		ret = btrfs_update_quoto_limit(trans, dstgroup, fs_info);
+		if (ret)
 			goto unlock;
-		}
 	}
 
 	if (srcid) {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item()
  2022-11-15 17:17 [PATCH v4 0/3] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
  2022-11-15 17:17 ` [PATCH v4 1/3] btrfs: add might_sleep() to some places " ChenXiaoSong
  2022-11-15 17:17 ` [PATCH v4 2/3] btrfs: qgroup: introduce btrfs_update_quoto_limit() helper ChenXiaoSong
@ 2022-11-15 17:17 ` ChenXiaoSong
  2022-11-15 16:22   ` ChenXiaoSong
  2022-11-15 22:50   ` Qu Wenruo
  2 siblings, 2 replies; 13+ messages in thread
From: ChenXiaoSong @ 2022-11-15 17:17 UTC (permalink / raw)
  To: clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, chenxiaosong2, zhangxiaoxu5, yanaijie,
	quwenruo.btrfs, wqu

Syzkaller reported BUG as follows:

  BUG: sleeping function called from invalid context at
       include/linux/sched/mm.h:274
  Call Trace:
   <TASK>
   dump_stack_lvl+0xcd/0x134
   __might_resched.cold+0x222/0x26b
   kmem_cache_alloc+0x2e7/0x3c0
   update_qgroup_limit_item+0xe1/0x390
   btrfs_qgroup_inherit+0x147b/0x1ee0
   create_subvol+0x4eb/0x1710
   btrfs_mksubvol+0xfe5/0x13f0
   __btrfs_ioctl_snap_create+0x2b0/0x430
   btrfs_ioctl_snap_create_v2+0x25a/0x520
   btrfs_ioctl+0x2a1c/0x5ce0
   __x64_sys_ioctl+0x193/0x200
   do_syscall_64+0x35/0x80

Fix this by delaying the limit item updates until unlock the spin lock.

Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
---
 fs/btrfs/qgroup.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index ca609a70d067..f84507ca3b99 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2867,6 +2867,8 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 	bool need_rescan = false;
 	u32 level_size = 0;
 	u64 nums;
+	bool update_limit = false;
+	int err;
 
 	/*
 	 * There are only two callers of this function.
@@ -2957,10 +2959,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 		dstgroup->max_excl = inherit->lim.max_excl;
 		dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
 		dstgroup->rsv_excl = inherit->lim.rsv_excl;
-
-		ret = btrfs_update_quoto_limit(trans, dstgroup, fs_info);
-		if (ret)
-			goto unlock;
+		update_limit = true;
 	}
 
 	if (srcid) {
@@ -2987,6 +2986,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 		dstgroup->max_excl = srcgroup->max_excl;
 		dstgroup->rsv_rfer = srcgroup->rsv_rfer;
 		dstgroup->rsv_excl = srcgroup->rsv_excl;
+		update_limit = false;
 
 		qgroup_dirty(fs_info, dstgroup);
 		qgroup_dirty(fs_info, srcgroup);
@@ -3055,6 +3055,11 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 
 unlock:
 	spin_unlock(&fs_info->qgroup_lock);
+	if (update_limit) {
+		err = btrfs_update_quoto_limit(trans, dstgroup, fs_info);
+		if (err)
+			ret = err;
+	}
 	if (!ret)
 		ret = btrfs_sysfs_add_one_qgroup(fs_info, dstgroup);
 out:
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/3] btrfs: qgroup: introduce btrfs_update_quoto_limit() helper
  2022-11-15 17:17 ` [PATCH v4 2/3] btrfs: qgroup: introduce btrfs_update_quoto_limit() helper ChenXiaoSong
@ 2022-11-15 17:33   ` David Sterba
  0 siblings, 0 replies; 13+ messages in thread
From: David Sterba @ 2022-11-15 17:33 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: clm, josef, dsterba, linux-btrfs, linux-kernel, zhangxiaoxu5,
	yanaijie, quwenruo.btrfs, wqu

On Wed, Nov 16, 2022 at 01:17:08AM +0800, ChenXiaoSong wrote:
> No functional changed. Just simplify the code.

Please write some description of the change, like "factor out quota
limit update that also marks qgroup as inconsistent if it fals".

> Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
> ---
>  fs/btrfs/qgroup.c | 34 +++++++++++++++++-----------------
>  1 file changed, 17 insertions(+), 17 deletions(-)
> 
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index d0480b9c6c86..ca609a70d067 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -1677,6 +1677,19 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
>  	return ret;
>  }
>  
> +static int btrfs_update_quoto_limit(struct btrfs_trans_handle *trans,

Typo 'quoto' and it should rather be qgroup as the limit is related to a
qgroup, quota is usually in connection with the whole subsystem.

> +				    struct btrfs_qgroup *qgroup,
> +				    struct btrfs_fs_info *fs_info)
> +{
> +	int ret = update_qgroup_limit_item(trans, qgroup);
> +	if (ret) {
> +		qgroup_mark_inconsistent(fs_info);
> +		btrfs_info(fs_info, "unable to update quota limit for %llu",
> +			   qgroup->qgroupid);
> +	}
> +	return ret;
> +}
> +
>  int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid,
>  		       struct btrfs_qgroup_limit *limit)
>  {
> @@ -1742,13 +1755,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid,
>  
>  	spin_unlock(&fs_info->qgroup_lock);
>  
> -	ret = update_qgroup_limit_item(trans, qgroup);
> -	if (ret) {
> -		qgroup_mark_inconsistent(fs_info);
> -		btrfs_info(fs_info, "unable to update quota limit for %llu",
> -		       qgroupid);
> -	}
> -
> +	ret = btrfs_update_quoto_limit(trans, qgroup, fs_info);
>  out:
>  	mutex_unlock(&fs_info->qgroup_ioctl_lock);
>  	return ret;
> @@ -2824,9 +2831,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
>  		ret = update_qgroup_info_item(trans, qgroup);
>  		if (ret)
>  			qgroup_mark_inconsistent(fs_info);
> -		ret = update_qgroup_limit_item(trans, qgroup);
> -		if (ret)
> -			qgroup_mark_inconsistent(fs_info);
> +		ret = btrfs_update_quoto_limit(trans, qgroup, fs_info);
>  		spin_lock(&fs_info->qgroup_lock);
>  	}
>  	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
> @@ -2953,14 +2958,9 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
>  		dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
>  		dstgroup->rsv_excl = inherit->lim.rsv_excl;
>  
> -		ret = update_qgroup_limit_item(trans, dstgroup);
> -		if (ret) {
> -			qgroup_mark_inconsistent(fs_info);
> -			btrfs_info(fs_info,
> -				   "unable to update quota limit for %llu",
> -				   dstgroup->qgroupid);
> +		ret = btrfs_update_quoto_limit(trans, dstgroup, fs_info);
> +		if (ret)
>  			goto unlock;
> -		}
>  	}
>  
>  	if (srcid) {
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-15 17:17 ` [PATCH v4 1/3] btrfs: add might_sleep() to some places " ChenXiaoSong
@ 2022-11-15 17:41   ` David Sterba
  2022-11-15 22:48   ` Qu Wenruo
  1 sibling, 0 replies; 13+ messages in thread
From: David Sterba @ 2022-11-15 17:41 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: clm, josef, dsterba, linux-btrfs, linux-kernel, zhangxiaoxu5,
	yanaijie, quwenruo.btrfs, wqu

On Wed, Nov 16, 2022 at 01:17:07AM +0800, ChenXiaoSong wrote:
> As the potential sleeping under spin lock is hard to spot, we should add
> might_sleep() to some places.
> 
> Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
> ---
>  fs/btrfs/ctree.c  | 2 ++
>  fs/btrfs/qgroup.c | 2 ++
>  2 files changed, 4 insertions(+)
> 
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index a9543f01184c..809053e9cfde 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -1934,6 +1934,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
>  	int min_write_lock_level;
>  	int prev_cmp;
>  
> +	might_sleep();

This needs some explanation in the changelog, the reason was mentioned
in some past patch iteration that it's due to potential IO fi the blocks
are not cached.

> +
>  	lowest_level = p->lowest_level;
>  	WARN_ON(lowest_level && ins_len > 0);
>  	WARN_ON(p->nodes[0] != NULL);
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index 9334c3157c22..d0480b9c6c86 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -779,6 +779,8 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
>  	int ret;
>  	int slot;
>  
> +	might_sleep();

This one is redundant, no? There's call to btrfs_search_slot a few lines
below.

> +
>  	key.objectid = 0;
>  	key.type = BTRFS_QGROUP_LIMIT_KEY;
>  	key.offset = qgroup->qgroupid;
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-15 17:17 ` [PATCH v4 1/3] btrfs: add might_sleep() to some places " ChenXiaoSong
  2022-11-15 17:41   ` David Sterba
@ 2022-11-15 22:48   ` Qu Wenruo
  2022-11-16  8:09     ` ChenXiaoSong
  1 sibling, 1 reply; 13+ messages in thread
From: Qu Wenruo @ 2022-11-15 22:48 UTC (permalink / raw)
  To: ChenXiaoSong, clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, zhangxiaoxu5, yanaijie, wqu



On 2022/11/16 01:17, ChenXiaoSong wrote:
> As the potential sleeping under spin lock is hard to spot, we should add
> might_sleep() to some places.
> 
> Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>

Looks good.

We may want to add more in other locations, but this is really a good start.

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu
> ---
>   fs/btrfs/ctree.c  | 2 ++
>   fs/btrfs/qgroup.c | 2 ++
>   2 files changed, 4 insertions(+)
> 
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index a9543f01184c..809053e9cfde 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -1934,6 +1934,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
>   	int min_write_lock_level;
>   	int prev_cmp;
>   
> +	might_sleep();
> +
>   	lowest_level = p->lowest_level;
>   	WARN_ON(lowest_level && ins_len > 0);
>   	WARN_ON(p->nodes[0] != NULL);
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index 9334c3157c22..d0480b9c6c86 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -779,6 +779,8 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
>   	int ret;
>   	int slot;
>   
> +	might_sleep();
> +
>   	key.objectid = 0;
>   	key.type = BTRFS_QGROUP_LIMIT_KEY;
>   	key.offset = qgroup->qgroupid;

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item()
  2022-11-15 17:17 ` [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
  2022-11-15 16:22   ` ChenXiaoSong
@ 2022-11-15 22:50   ` Qu Wenruo
  1 sibling, 0 replies; 13+ messages in thread
From: Qu Wenruo @ 2022-11-15 22:50 UTC (permalink / raw)
  To: ChenXiaoSong, clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, zhangxiaoxu5, yanaijie, wqu



On 2022/11/16 01:17, ChenXiaoSong wrote:
> Syzkaller reported BUG as follows:
> 
>    BUG: sleeping function called from invalid context at
>         include/linux/sched/mm.h:274
>    Call Trace:
>     <TASK>
>     dump_stack_lvl+0xcd/0x134
>     __might_resched.cold+0x222/0x26b
>     kmem_cache_alloc+0x2e7/0x3c0
>     update_qgroup_limit_item+0xe1/0x390
>     btrfs_qgroup_inherit+0x147b/0x1ee0
>     create_subvol+0x4eb/0x1710
>     btrfs_mksubvol+0xfe5/0x13f0
>     __btrfs_ioctl_snap_create+0x2b0/0x430
>     btrfs_ioctl_snap_create_v2+0x25a/0x520
>     btrfs_ioctl+0x2a1c/0x5ce0
>     __x64_sys_ioctl+0x193/0x200
>     do_syscall_64+0x35/0x80
> 
> Fix this by delaying the limit item updates until unlock the spin lock.
> 
> Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
> ---
>   fs/btrfs/qgroup.c | 13 +++++++++----
>   1 file changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index ca609a70d067..f84507ca3b99 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -2867,6 +2867,8 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
>   	bool need_rescan = false;
>   	u32 level_size = 0;
>   	u64 nums;
> +	bool update_limit = false;
> +	int err;
>   
>   	/*
>   	 * There are only two callers of this function.
> @@ -2957,10 +2959,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
>   		dstgroup->max_excl = inherit->lim.max_excl;
>   		dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
>   		dstgroup->rsv_excl = inherit->lim.rsv_excl;
> -
> -		ret = btrfs_update_quoto_limit(trans, dstgroup, fs_info);
> -		if (ret)
> -			goto unlock;
> +		update_limit = true;

Nope, just call qgroup_dirty() for @dstgroup.

Thanks,
Qu
>   	}
>   
>   	if (srcid) {
> @@ -2987,6 +2986,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
>   		dstgroup->max_excl = srcgroup->max_excl;
>   		dstgroup->rsv_rfer = srcgroup->rsv_rfer;
>   		dstgroup->rsv_excl = srcgroup->rsv_excl;
> +		update_limit = false;
>   
>   		qgroup_dirty(fs_info, dstgroup);
>   		qgroup_dirty(fs_info, srcgroup);
> @@ -3055,6 +3055,11 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
>   
>   unlock:
>   	spin_unlock(&fs_info->qgroup_lock);
> +	if (update_limit) {
> +		err = btrfs_update_quoto_limit(trans, dstgroup, fs_info);
> +		if (err)
> +			ret = err;
> +	}
>   	if (!ret)
>   		ret = btrfs_sysfs_add_one_qgroup(fs_info, dstgroup);
>   out:

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-15 22:48   ` Qu Wenruo
@ 2022-11-16  8:09     ` ChenXiaoSong
  2022-11-16  8:43       ` Qu Wenruo
  0 siblings, 1 reply; 13+ messages in thread
From: ChenXiaoSong @ 2022-11-16  8:09 UTC (permalink / raw)
  To: Qu Wenruo, clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, zhangxiaoxu5, yanaijie, wqu

在 2022/11/16 6:48, Qu Wenruo 写道:
> Looks good.
> 
> We may want to add more in other locations, but this is really a good 
> start.
> 
> Reviewed-by: Qu Wenruo <wqu@suse.com>
> 
> Thanks,
> Qu

If I just add might_sleep() in btrfs_alloc_path() and 
btrfs_search_slot(), is it reasonable?

Or just add might_sleep() to one place in update_qgroup_limit_item() ?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-16  8:09     ` ChenXiaoSong
@ 2022-11-16  8:43       ` Qu Wenruo
  2022-11-16 12:24         ` David Sterba
  0 siblings, 1 reply; 13+ messages in thread
From: Qu Wenruo @ 2022-11-16  8:43 UTC (permalink / raw)
  To: ChenXiaoSong, clm, josef, dsterba
  Cc: linux-btrfs, linux-kernel, zhangxiaoxu5, yanaijie, wqu



On 2022/11/16 16:09, ChenXiaoSong wrote:
> 在 2022/11/16 6:48, Qu Wenruo 写道:
>> Looks good.
>>
>> We may want to add more in other locations, but this is really a good 
>> start.
>>
>> Reviewed-by: Qu Wenruo <wqu@suse.com>
>>
>> Thanks,
>> Qu
> 
> If I just add might_sleep() in btrfs_alloc_path() and 
> btrfs_search_slot(), is it reasonable?

Adding it to btrfs_search_slot() is definitely correct.

But why for btrfs_alloc_path()? Wouldn't kmem_cache_zalloc() itself 
already do the might_sleep_if() somewhere?

I just looked the call chain, and indeed it is doing the check already:

btrfs_alloc_path()
|- kmem_cache_zalloc()
    |- kmem_cache_alloc()
       |- __kmem_cache_alloc_lru()
          |- slab_alloc()
             |- slab_alloc_node()
                |- slab_pre_alloc_hook()
                   |- might_alloc()
                      |- might_sleep_if()

Thanks,
Qu

> 
> Or just add might_sleep() to one place in update_qgroup_limit_item() ?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-16  8:43       ` Qu Wenruo
@ 2022-11-16 12:24         ` David Sterba
  2022-11-16 12:26           ` Qu Wenruo
  0 siblings, 1 reply; 13+ messages in thread
From: David Sterba @ 2022-11-16 12:24 UTC (permalink / raw)
  To: Qu Wenruo
  Cc: ChenXiaoSong, clm, josef, dsterba, linux-btrfs, linux-kernel,
	zhangxiaoxu5, yanaijie, wqu

On Wed, Nov 16, 2022 at 04:43:50PM +0800, Qu Wenruo wrote:
> 
> 
> On 2022/11/16 16:09, ChenXiaoSong wrote:
> > 在 2022/11/16 6:48, Qu Wenruo 写道:
> >> Looks good.
> >>
> >> We may want to add more in other locations, but this is really a good 
> >> start.
> >>
> >> Reviewed-by: Qu Wenruo <wqu@suse.com>
> >>
> >> Thanks,
> >> Qu
> > 
> > If I just add might_sleep() in btrfs_alloc_path() and 
> > btrfs_search_slot(), is it reasonable?
> 
> Adding it to btrfs_search_slot() is definitely correct.
> 
> But why for btrfs_alloc_path()? Wouldn't kmem_cache_zalloc() itself 
> already do the might_sleep_if() somewhere?
> 
> I just looked the call chain, and indeed it is doing the check already:
> 
> btrfs_alloc_path()
> |- kmem_cache_zalloc()
>     |- kmem_cache_alloc()
>        |- __kmem_cache_alloc_lru()
>           |- slab_alloc()
>              |- slab_alloc_node()
>                 |- slab_pre_alloc_hook()
>                    |- might_alloc()
>                       |- might_sleep_if()

The call chaing is unconditional so the check will always happen but the
condition itself in might_sleep_if does not recognize GFP_NOFS:

 34 static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
 35 {
 36         return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
 37 }

#define GFP_NOFS        (__GFP_RECLAIM | __GFP_IO)

And I think the qgroup limit was exactly a spin lock over btrfs_path_alloc so
it did not help. An might_sleep() inside btrfs_path_alloc() is a very minimal
but reliable check we could add, the paths are used in many places so it would
increase the coverage.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/3] btrfs: add might_sleep() to some places in update_qgroup_limit_item()
  2022-11-16 12:24         ` David Sterba
@ 2022-11-16 12:26           ` Qu Wenruo
  0 siblings, 0 replies; 13+ messages in thread
From: Qu Wenruo @ 2022-11-16 12:26 UTC (permalink / raw)
  To: dsterba
  Cc: ChenXiaoSong, clm, josef, dsterba, linux-btrfs, linux-kernel,
	zhangxiaoxu5, yanaijie, wqu



On 2022/11/16 20:24, David Sterba wrote:
> On Wed, Nov 16, 2022 at 04:43:50PM +0800, Qu Wenruo wrote:
>>
>>
>> On 2022/11/16 16:09, ChenXiaoSong wrote:
>>> 在 2022/11/16 6:48, Qu Wenruo 写道:
>>>> Looks good.
>>>>
>>>> We may want to add more in other locations, but this is really a good
>>>> start.
>>>>
>>>> Reviewed-by: Qu Wenruo <wqu@suse.com>
>>>>
>>>> Thanks,
>>>> Qu
>>>
>>> If I just add might_sleep() in btrfs_alloc_path() and
>>> btrfs_search_slot(), is it reasonable?
>>
>> Adding it to btrfs_search_slot() is definitely correct.
>>
>> But why for btrfs_alloc_path()? Wouldn't kmem_cache_zalloc() itself
>> already do the might_sleep_if() somewhere?
>>
>> I just looked the call chain, and indeed it is doing the check already:
>>
>> btrfs_alloc_path()
>> |- kmem_cache_zalloc()
>>      |- kmem_cache_alloc()
>>         |- __kmem_cache_alloc_lru()
>>            |- slab_alloc()
>>               |- slab_alloc_node()
>>                  |- slab_pre_alloc_hook()
>>                     |- might_alloc()
>>                        |- might_sleep_if()
> 
> The call chaing is unconditional so the check will always happen but the
> condition itself in might_sleep_if does not recognize GFP_NOFS:
> 
>   34 static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
>   35 {
>   36         return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
>   37 }
> 
> #define GFP_NOFS        (__GFP_RECLAIM | __GFP_IO)
> 
> And I think the qgroup limit was exactly a spin lock over btrfs_path_alloc so
> it did not help. An might_sleep() inside btrfs_path_alloc() is a very minimal
> but reliable check we could add, the paths are used in many places so it would
> increase the coverage.

OK, then it makes sense now for btrfs_alloc_path().

But I still believe this looks like a bug in gfpflags_allow_blocking()...

Thanks,
Qu

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-11-16 12:29 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-15 17:17 [PATCH v4 0/3] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
2022-11-15 17:17 ` [PATCH v4 1/3] btrfs: add might_sleep() to some places " ChenXiaoSong
2022-11-15 17:41   ` David Sterba
2022-11-15 22:48   ` Qu Wenruo
2022-11-16  8:09     ` ChenXiaoSong
2022-11-16  8:43       ` Qu Wenruo
2022-11-16 12:24         ` David Sterba
2022-11-16 12:26           ` Qu Wenruo
2022-11-15 17:17 ` [PATCH v4 2/3] btrfs: qgroup: introduce btrfs_update_quoto_limit() helper ChenXiaoSong
2022-11-15 17:33   ` David Sterba
2022-11-15 17:17 ` [PATCH v4 3/3] btrfs: qgroup: fix sleep from invalid context bug in update_qgroup_limit_item() ChenXiaoSong
2022-11-15 16:22   ` ChenXiaoSong
2022-11-15 22:50   ` Qu Wenruo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox