2022-11-16 13:33:43

by ChenXiaoSong

[permalink] [raw]
Subject: [PATCH v6 0/2] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item()

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 calling qgroup_dirty() on @dstqgroup, and update limit item in
btrfs_run_qgroups() later.

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

ChenXiaoSong (2):
btrfs: add might_sleep() to some places in update_qgroup_limit_item()
btrfs: qgroup: fix sleep from invalid context bug in
update_qgroup_limit_item()

fs/btrfs/ctree.c | 4 ++++
fs/btrfs/qgroup.c | 9 +--------
2 files changed, 5 insertions(+), 8 deletions(-)

--
2.31.1



2022-11-16 13:59:32

by ChenXiaoSong

[permalink] [raw]
Subject: [PATCH v6 1/2] btrfs: add might_sleep() to some places in update_qgroup_limit_item()

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

As the potential sleeping under spin lock is hard to spot, we should add
might_sleep() to btrfs_alloc_path() and btrfs_search_slot().

Signed-off-by: ChenXiaoSong <[email protected]>
---
fs/btrfs/ctree.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index a9543f01184c..1cd0d00ef328 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -78,6 +78,8 @@ size_t __attribute_const__ btrfs_get_num_csums(void)

struct btrfs_path *btrfs_alloc_path(void)
{
+ might_sleep();
+
return kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);
}

@@ -1934,6 +1936,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);
--
2.31.1


2022-11-18 17:05:48

by David Sterba

[permalink] [raw]
Subject: Re: [PATCH v6 0/2] btrfs: fix sleep from invalid context bug in update_qgroup_limit_item()

On Wed, Nov 16, 2022 at 10:23:52PM +0800, ChenXiaoSong wrote:
> 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 calling qgroup_dirty() on @dstqgroup, and update limit item in
> btrfs_run_qgroups() later.
>
> By the way, add might_sleep() to some places.
>
> ChenXiaoSong (2):
> btrfs: add might_sleep() to some places in update_qgroup_limit_item()
> btrfs: qgroup: fix sleep from invalid context bug in
> update_qgroup_limit_item()

Added to misc-next with updated subjects and changelogs, thanks.