From: Nikolay Borisov <nborisov@suse.com>
To: Qu Wenruo <quwenruo.btrfs@gmx.com>, Qu Wenruo <wqu@suse.com>,
linux-btrfs@vger.kernel.org
Subject: Re: [PATCH v3 2/3] btrfs: backref: Implement btrfs_backref_iterator_next()
Date: Mon, 17 Feb 2020 16:13:48 +0200 [thread overview]
Message-ID: <c75fb84e-fa6b-a666-a30a-811d95c6735a@suse.com> (raw)
In-Reply-To: <3aadef5b-7bd2-b830-869f-67de417a4600@gmx.com>
On 17.02.20 г. 13:45 ч., Qu Wenruo wrote:
>
>
> On 2020/2/17 下午7:42, Nikolay Borisov wrote:
>>
>>
>> On 17.02.20 г. 13:29 ч., Qu Wenruo wrote:
>>>
>>>
>>> On 2020/2/17 下午6:47, Nikolay Borisov wrote:
>>>>
>>>>
>>>> On 17.02.20 г. 8:31 ч., Qu Wenruo wrote:
>>>>> This function will go next inline/keyed backref for
>>>>> btrfs_backref_iterator infrastructure.
>>>>>
>>>>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>>>>> ---
>>>>> fs/btrfs/backref.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>> fs/btrfs/backref.h | 34 +++++++++++++++++++++++++++++++++
>>>>> 2 files changed, 81 insertions(+)
>>>>>
>>>>> diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
>>>>> index 8bd5e067831c..fb0abe344851 100644
>>>>> --- a/fs/btrfs/backref.c
>>>>> +++ b/fs/btrfs/backref.c
>>>>> @@ -2310,3 +2310,50 @@ int btrfs_backref_iterator_start(struct btrfs_backref_iterator *iterator,
>>>>> btrfs_backref_iterator_release(iterator);
>>>>> return ret;
>>>>> }
>>>>> +
>>>>> +int btrfs_backref_iterator_next(struct btrfs_backref_iterator *iterator)
>>>>
>>>> Document the return values: 0 in case there are more backerfs for the
>>>> given bytenr or 1 in case there are'nt. And a negative value in case of
>>>> error.
>>>>
>>>>> +{
>>>>> + struct extent_buffer *eb = btrfs_backref_get_eb(iterator);
>>>>> + struct btrfs_path *path = iterator->path;
>>>>> + struct btrfs_extent_inline_ref *iref;
>>>>> + int ret;
>>>>> + u32 size;
>>>>> +
>>>>> + if (btrfs_backref_iterator_is_inline_ref(iterator)) {
>>>>> + /* We're still inside the inline refs */
>>>>> + if (btrfs_backref_has_tree_block_info(iterator)) {
>>>>> + /* First tree block info */
>>>>> + size = sizeof(struct btrfs_tree_block_info);
>>>>> + } else {
>>>>> + /* Use inline ref type to determine the size */
>>>>> + int type;
>>>>> +
>>>>> + iref = (struct btrfs_extent_inline_ref *)
>>>>> + (iterator->cur_ptr);
>>>>> + type = btrfs_extent_inline_ref_type(eb, iref);
>>>>> +
>>>>> + size = btrfs_extent_inline_ref_size(type);
>>>>> + }
>>>>> + iterator->cur_ptr += size;
>>>>> + if (iterator->cur_ptr < iterator->end_ptr)
>>>>> + return 0;
>>>>> +
>>>>> + /* All inline items iterated, fall through */
>>>>> + }
>>>>
>>>> This if could be rewritten as:
>>>> if (btrfs_backref_iterator_is_inline_ref(iterator) && iterator->cur_ptr
>>>> < iterator->end_ptr)
>>>>
>>>> what this achieves is:
>>>>
>>>> 1. Clarity that this whole branch is executed only if we are within the
>>>> inline refs limits
>>>> 2. It also optimises that function since in the current version, after
>>>> the last inline backref has been processed iterator->cur_ptr ==
>>>> iterator->end_ptr. On the next call to btrfs_backref_iterator_next you
>>>> will execute (needlessly)
>>>>
>>>> (struct btrfs_extent_inline_ref *) (iterator->cur_ptr);
>>>> type = btrfs_extent_inline_ref_type(eb, iref);
>>>> size = btrfs_extent_inline_ref_size(type);
>>>> iterator->cur_ptr += size;
>>>> only to fail "if (iterator->cur_ptr < iterator->end_ptr)" check and
>>>> continue processing keyed items.
>>>>
>>>> As a matter of fact you will be reading past the metadata_item since
>>>> cur_ptr will be at the end of them and any deferences will read from the
>>>> next item this might not cause a crash but it's still wrong.
>>>
>>> This shouldn't happen, as we must ensure the cur_ptr < item_end for callers.
>>
>>
>> How are you ensuring this? Before processing the last inline ref
>> cur_ptr would be end_ptr - btrfs_extent_inline_ref_size(type);
>
> Firstly, in _start() call, we can easily check if we have any inline refs.
>
> If no, search next item.
> If yes, return cur_ptr which points to the current inline extent ref.
>
> Secondly, in _next() call, we keep current check. Increase cur_ptr, then
> check against ptr_end.
>
> So that, all backref_iter callers will get a cur_ptr that is always
> smaller than ptr_end.
Apparently not, btrfs/003 with the following assert:
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index fb0abe344851..403a75f0c99c 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -2328,6 +2328,7 @@ int btrfs_backref_iterator_next(struct
btrfs_backref_iterator *iterator)
/* Use inline ref type to determine the size */
int type;
+ ASSERT(iterator->cur_ptr < iterator->end_ptr);
iref = (struct btrfs_extent_inline_ref *)
(iterator->cur_ptr);
type = btrfs_extent_inline_ref_type(eb, iref);
Trigger:
[ 58.884441] assertion failed: iterator->cur_ptr < iterator->end_ptr,
in fs/btrfs/backref.c:2331
>
> Thanks,
> Qu
>>
>> After it's processed cur_ptr == end_ptr. THen you will do another call
>> to btrfs_backref_iterator_next which will do the same calculation? What
>> am I missing?
>>
>>>
>>> For the _next() call, the check after increased cur_ptr check it's OK.
>>>
>>> But it's a problem for _start() call, as we may have a case where an
>>> EXTENT_ITEM/METADATA_ITEM has no inlined ref.
>>>
>>> I'll fix this in next version.
>>>
>>> Thanks,
>>> Qu
>>>
>>>>
>>>>
>>>>> + /* We're at keyed items, there is no inline item, just go next item */
>>>>> + ret = btrfs_next_item(iterator->fs_info->extent_root, iterator->path);
>>>>> + if (ret > 0 || ret < 0)
>>>>> + return ret;
>>>>
>>>> nit: if (ret != 0) return ret;
>>>>
>>>> <snip>
>>>>
next prev parent reply other threads:[~2020-02-17 14:13 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-17 6:31 [PATCH v3 0/3] Btrfs: relocation: Refactor build_backref_tree() using btrfs_backref_iterator infrastructure Qu Wenruo
2020-02-17 6:31 ` [PATCH v3 1/3] btrfs: backref: Introduce the skeleton of btrfs_backref_iterator Qu Wenruo
2020-02-17 10:18 ` Nikolay Borisov
2020-02-17 6:31 ` [PATCH v3 2/3] btrfs: backref: Implement btrfs_backref_iterator_next() Qu Wenruo
2020-02-17 10:47 ` Nikolay Borisov
2020-02-17 11:29 ` Qu Wenruo
2020-02-17 11:42 ` Nikolay Borisov
2020-02-17 11:45 ` Qu Wenruo
2020-02-17 14:13 ` Nikolay Borisov [this message]
2020-02-17 23:59 ` Qu Wenruo
2020-02-17 6:31 ` [PATCH v3 3/3] btrfs: relocation: Use btrfs_backref_iterator infrastructure Qu Wenruo
2020-02-17 11:32 ` Nikolay Borisov
2020-02-17 16:01 ` Nikolay Borisov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c75fb84e-fa6b-a666-a30a-811d95c6735a@suse.com \
--to=nborisov@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=quwenruo.btrfs@gmx.com \
--cc=wqu@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).