* 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