Re: [PATCH v3 1/3] btrfs: qgroup: allow btrfs_qgroup_reserve_data() to revert the range it just set without releasing other existing ranges

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 2020/7/8 下午10:09, Josef Bacik wrote:
> On 7/8/20 2:24 AM, Qu Wenruo wrote:
>> [PROBLEM]
>> Before this patch, when btrfs_qgroup_reserve_data() fails, we free all
>> reserved space of the changeset.
>>
>> For example:
>>     ret = btrfs_qgroup_reserve_data(inode, changeset, 0, SZ_1M);
>>     ret = btrfs_qgroup_reserve_data(inode, changeset, SZ_1M, SZ_1M);
>>     ret = btrfs_qgroup_reserve_data(inode, changeset, SZ_2M, SZ_1M);
>>
>> If the last btrfs_qgroup_reserve_data() failed, it will release all [0,
>> 3M) range.
>>
>> This behavior is kinda OK for now, as when we hit -EDQUOT, we normally
>> go error handling and need to release all reserved ranges anyway.
>>
>> But this also means the following call is not possible:
>>     ret = btrfs_qgroup_reserve_data();
>>     if (ret == -EDQUOT) {
>>         /* Do something to free some qgroup space */
>>         ret = btrfs_qgroup_reserve_data();
>>     }
>>
>> As if the first btrfs_qgroup_reserve_data() fails, it will free all
>> reserved qgroup space.
>>
>> [CAUSE]
>> This is because we release all reserved ranges when
>> btrfs_qgroup_reserve_data() fails.
>>
>> [FIX]
>> This patch will implement a new function, qgroup_revert(), to iterate
>> through the ulist nodes, to find any nodes in the failure range, and
>> remove the EXTENT_QGROUP_RESERVED bits from the io_tree, and decrease
>> the extent_changeset::bytes_changed, so that we can revert to previous
>> status.
>>
>> This allows later patches to retry btrfs_qgroup_reserve_data() if EDQUOT
>> happens.
>>
>> Suggested-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
>> Signed-off-by: Qu Wenruo <wqu@xxxxxxxx>
>> ---
>>   fs/btrfs/qgroup.c | 90 +++++++++++++++++++++++++++++++++++++++--------
>>   1 file changed, 75 insertions(+), 15 deletions(-)
>>
>> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
>> index ee0ad33b659c..84a452dea3f9 100644
>> --- a/fs/btrfs/qgroup.c
>> +++ b/fs/btrfs/qgroup.c
>> @@ -3447,6 +3447,71 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info
>> *fs_info)
>>       }
>>   }
>>   +static int qgroup_revert(struct btrfs_inode *inode,
>> +            struct extent_changeset *reserved, u64 start,
>> +            u64 len)
>> +{
>> +    struct rb_node *n = reserved->range_changed.root.rb_node;
>> +    struct ulist_node *entry = NULL;
>> +    int ret = 0;
>> +
>> +    while (n) {
>> +        entry = rb_entry(n, struct ulist_node, rb_node);
>> +        if (entry->val < start)
>> +            n = n->rb_right;
>> +        else if (entry)
>> +            n = n->rb_left;
>> +        else
>> +            break;
>> +    }
>> +    /* Empty changeset */
>> +    if (!entry)
>> +        goto out;
>
> Don't need the goto out here, just return ret;
>
>> +
>> +    if (entry->val > start && rb_prev(&entry->rb_node))
>> +        entry = rb_entry(rb_prev(&entry->rb_node), struct ulist_node,
>> +                 rb_node);
>> +
>> +    n = &entry->rb_node;
>> +    while (n) {
>
> for (n = &entry->rb_node; n; n = rb_next(n)) {

You get into the trap!

Since @n can be deleted from the tree, it needs the @tmp to record
what's the real next node.

But I can still use for loop with @tmp involved though.

Thanks,
Qu
>
> Thanks,
>
> Josef




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux