On 2019/6/6 上午12:32, David Sterba wrote:
> On Tue, Apr 16, 2019 at 06:21:43PM +0800, Qu Wenruo wrote:
>> There is a hidden call loop which can trigger itself:
>>
>> btrfs_reserve_extent() <--|
>> |- do_chunk_alloc() |
>> |- btrfs_alloc_chunk() |
>> |- btrfs_insert_item() |
>> |- btrfs_reserve_extent() <--|
>>
>> Currently, we're using root->ref_cows to determine whether we should do
>> chunk prealloc to avoid such loop.
>>
>> But that's still a hidden trap. Instead of solving it using some hidden
>> tricks, this patch will make chunk/block group allocation exclusive.
>>
>> Now if do_chunk_alloc() determines to alloc chunk, it will set a special
>> flag in transaction handler so it new do_chunk_alloc() will refuse to
>> allocate new chunk until current chunk allocation finishes.
>>
>> Signed-off-by: Qu Wenruo <wqu@xxxxxxxx>
>> ---
>> check/main.c | 2 +-
>> extent-tree.c | 12 ++++++++++++
>> transaction.c | 3 ++-
>> transaction.h | 3 ++-
>> 4 files changed, 17 insertions(+), 3 deletions(-)
>>
>> diff --git a/check/main.c b/check/main.c
>> index 683c322eba6f..121be4b73c4f 100644
>> --- a/check/main.c
>> +++ b/check/main.c
>> @@ -10185,7 +10185,7 @@ int cmd_check(int argc, char **argv)
>> goto close_out;
>> }
>>
>> - trans->reinit_extent_tree = true;
>> + trans->reinit_extent_tree = 1;
>> if (init_extent_tree) {
>> printf("Creating a new extent tree\n");
>> ret = reinit_extent_tree(trans, info,
>> diff --git a/extent-tree.c b/extent-tree.c
>> index 8c9cdeff3b02..e25ddf02e5cc 100644
>> --- a/extent-tree.c
>> +++ b/extent-tree.c
>> @@ -1873,10 +1873,21 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
>> (flags & BTRFS_BLOCK_GROUP_SYSTEM))
>> return 0;
>>
>> + /*
>> + * We're going to allocate new chunk, during the process, we will
>> + * allocate new tree blocks, which can trigger new chunk allocation
>> + * again.
>> + * Avoid such loop call
>> + */
>> + if (trans->allocating_chunk)
>> + return 0;
>> + trans->allocating_chunk = 1;
>> +
>> ret = btrfs_alloc_chunk(trans, fs_info, &start, &num_bytes,
>> space_info->flags);
>> if (ret == -ENOSPC) {
>> space_info->full = 1;
>> + trans->allocating_chunk = 0;
>> return 0;
>> }
>>
>> @@ -1885,6 +1896,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
>> ret = btrfs_make_block_group(trans, fs_info, 0, space_info->flags,
>> start, num_bytes);
>> BUG_ON(ret);
>> + trans->allocating_chunk = 0;
>> return 0;
>> }
>>
>> diff --git a/transaction.c b/transaction.c
>> index 3a63988b0969..21377282f806 100644
>> --- a/transaction.c
>> +++ b/transaction.c
>> @@ -46,7 +46,8 @@ struct btrfs_trans_handle* btrfs_start_transaction(struct btrfs_root *root,
>> fs_info->generation++;
>> h->transid = fs_info->generation;
>> h->blocks_reserved = num_blocks;
>> - h->reinit_extent_tree = false;
>> + h->reinit_extent_tree = 0;
>> + h->allocating_chunk = 0;
>> root->last_trans = h->transid;
>> root->commit_root = root->node;
>> extent_buffer_get(root->node);
>> diff --git a/transaction.h b/transaction.h
>> index 34060252dd5c..b426cd112447 100644
>> --- a/transaction.h
>> +++ b/transaction.h
>> @@ -28,7 +28,8 @@ struct btrfs_trans_handle {
>> u64 transid;
>> u64 alloc_exclude_start;
>> u64 alloc_exclude_nr;
>> - bool reinit_extent_tree;
>> + unsigned int reinit_extent_tree:1;
>> + unsigned int allocating_chunk:1;
>
> Why do you switch reinit_extent_tree to the bit, this is an unrelated
> change. I'll drop it and update changelog with the 2M preallocation
> that was discussed.
>
Because in this patch, we're introducing new bit, thus to me it's pretty
valid to expanding old bool value into bits.
Thanks,
Qu
Attachment:
signature.asc
Description: OpenPGP digital signature
