From: Qu Wenruo <wqu@suse.com>
To: Naohiro Aota <Naohiro.Aota@wdc.com>
Cc: "linux-btrfs@vger.kernel.org" <linux-btrfs@vger.kernel.org>,
Johannes Thumshirn <Johannes.Thumshirn@wdc.com>,
"josef@toxicpanda.com" <josef@toxicpanda.com>
Subject: Re: [PATCH v5 3/5] btrfs: lock subpage ranges in one go for writepage_delalloc()
Date: Tue, 21 May 2024 18:15:32 +0930 [thread overview]
Message-ID: <30371f39-18b1-4c3f-af31-b4927eab99a5@suse.com> (raw)
In-Reply-To: <7oxv5xm6n4yg5r523pzm7hxql5pihrfylrducrsiwlk5k4jl7a@wxvlrl6w6cbu>
在 2024/5/21 17:41, Naohiro Aota 写道:
[...]
> Same here.
>
>> while (delalloc_start < page_end) {
>> delalloc_end = page_end;
>> if (!find_lock_delalloc_range(&inode->vfs_inode, page,
>> @@ -1240,15 +1249,68 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
>> delalloc_start = delalloc_end + 1;
>> continue;
>> }
>> -
>> - ret = btrfs_run_delalloc_range(inode, page, delalloc_start,
>> - delalloc_end, wbc);
>> - if (ret < 0)
>> - return ret;
>> -
>> + btrfs_folio_set_writer_lock(fs_info, folio, delalloc_start,
>> + min(delalloc_end, page_end) + 1 -
>> + delalloc_start);
>> + last_delalloc_end = delalloc_end;
>> delalloc_start = delalloc_end + 1;
>> }
>
> Can we bail out on the "if (!last_delalloc_end)" case? It would make the
> following code simpler.
Mind to explain it a little more?
Did you mean something like this:
while (delalloc_start < page_end) {
/* lock all subpage delalloc range code */
}
if (!last_delalloc_end)
goto finish;
while (delalloc_start < page_end) {
/* run the delalloc ranges code* /
}
If so, I can definitely go that way.
>
>> + delalloc_start = page_start;
>> + /* Run the delalloc ranges for above locked ranges. */
>> + while (last_delalloc_end && delalloc_start < page_end) {
>> + u64 found_start;
>> + u32 found_len;
>> + bool found;
>>
>> + if (!btrfs_is_subpage(fs_info, page->mapping)) {
>> + /*
>> + * For non-subpage case, the found delalloc range must
>> + * cover this page and there must be only one locked
>> + * delalloc range.
>> + */
>> + found_start = page_start;
>> + found_len = last_delalloc_end + 1 - found_start;
>> + found = true;
>> + } else {
>> + found = btrfs_subpage_find_writer_locked(fs_info, folio,
>> + delalloc_start, &found_start, &found_len);
>> + }
>> + if (!found)
>> + break;
>> + /*
>> + * The subpage range covers the last sector, the delalloc range may
>> + * end beyonds the page boundary, use the saved delalloc_end
>> + * instead.
>> + */
>> + if (found_start + found_len >= page_end)
>> + found_len = last_delalloc_end + 1 - found_start;
>> +
>> + if (ret < 0) {
>
> At first glance, it is strange because "ret" is not set above. But, it is
> executed when btrfs_run_delalloc_range() returns an error in an iteration,
> for the remaining iterations...
>
> I'd like to have a dedicated clean-up path ... but I agree it is difficult
> to make such cleanup loop clean.
I can add an extra bool to indicate if we have any error, but overall
it's not much different.
>
> Flipping the if-conditions looks better? Or, adding more comments would be nice.
I guess that would go this path, flipping the if conditions and extra
comments.
>
>> + /* Cleanup the remaining locked ranges. */
>> + unlock_extent(&inode->io_tree, found_start,
>> + found_start + found_len - 1, NULL);
>> + __unlock_for_delalloc(&inode->vfs_inode, page, found_start,
>> + found_start + found_len - 1);
>> + } else {
>> + ret = btrfs_run_delalloc_range(inode, page, found_start,
>> + found_start + found_len - 1, wbc);
>
> Also, what happens if the first range returns "1" and a later one returns
> "0"? Is it OK to override the "ret" for the case? Actually, I guess it
> won't happen now because (as said in patch 5) subpage disables an inline
> extent, but having an ASSERT() would be good to catch a future mistake.
It's not only inline but also compression can return 1.
Thankfully for subpage, inline is disabled, meanwhile compression can
only be done for a full page aligned range (start and end are both page
aligned).
Considering you're mentioning this, I would definitely add an ASSERT()
with comments explaining this.
Thanks for the feedback!
Qu
>
>> + }
>> + /*
>> + * Above btrfs_run_delalloc_range() may have unlocked the page,
>> + * Thus for the last range, we can not touch the page anymore.
>> + */
>> + if (found_start + found_len >= last_delalloc_end + 1)
>> + break;
>> +
>> + delalloc_start = found_start + found_len;
>> + }
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (last_delalloc_end)
>> + delalloc_end = last_delalloc_end;
>> + else
>> + delalloc_end = page_end;
>> /*
>> * delalloc_end is already one less than the total length, so
>> * we don't subtract one from PAGE_SIZE
>> @@ -1520,7 +1582,8 @@ static int __extent_writepage(struct page *page, struct btrfs_bio_ctrl *bio_ctrl
>> PAGE_SIZE, !ret);
>> mapping_set_error(page->mapping, ret);
>> }
>> - unlock_page(page);
>> +
>> + btrfs_folio_end_all_writers(inode_to_fs_info(inode), folio);
>> ASSERT(ret <= 0);
>> return ret;
>> }
>> diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c
>> index 3c957d03324e..81b862d7ab53 100644
>> --- a/fs/btrfs/subpage.c
>> +++ b/fs/btrfs/subpage.c
>> @@ -862,6 +862,7 @@ bool btrfs_subpage_find_writer_locked(const struct btrfs_fs_info *fs_info,
>> void btrfs_folio_end_all_writers(const struct btrfs_fs_info *fs_info,
>> struct folio *folio)
>> {
>> + struct btrfs_subpage *subpage = folio_get_private(folio);
>> u64 folio_start = folio_pos(folio);
>> u64 cur = folio_start;
>>
>> @@ -871,6 +872,11 @@ void btrfs_folio_end_all_writers(const struct btrfs_fs_info *fs_info,
>> return;
>> }
>>
>> + /* The page has no new delalloc range locked on it. Just plain unlock. */
>> + if (atomic_read(&subpage->writers) == 0) {
>> + folio_unlock(folio);
>> + return;
>> + }
>> while (cur < folio_start + PAGE_SIZE) {
>> u64 found_start;
>> u32 found_len;
>> --
>> 2.45.0
next prev parent reply other threads:[~2024-05-21 8:45 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-18 5:07 [PATCH v5 0/5] btrfs: subpage + zoned fixes Qu Wenruo
2024-05-18 5:07 ` [PATCH v5 1/5] btrfs: make __extent_writepage_io() to write specified range only Qu Wenruo
2024-05-21 7:23 ` Naohiro Aota
2024-05-18 5:07 ` [PATCH v5 2/5] btrfs: subpage: introduce helpers to handle subpage delalloc locking Qu Wenruo
2024-05-21 7:50 ` Naohiro Aota
2024-05-21 7:57 ` Qu Wenruo
2024-05-18 5:07 ` [PATCH v5 3/5] btrfs: lock subpage ranges in one go for writepage_delalloc() Qu Wenruo
2024-05-21 8:11 ` Naohiro Aota
2024-05-21 8:45 ` Qu Wenruo [this message]
2024-05-21 11:54 ` Naohiro Aota
2024-05-21 22:16 ` Qu Wenruo
2024-05-22 1:10 ` Naohiro Aota
2024-05-18 5:07 ` [PATCH v5 4/5] btrfs: do not clear page dirty inside extent_write_locked_range() Qu Wenruo
2024-05-18 5:07 ` [PATCH v5 5/5] btrfs: make extent_write_locked_range() to handle subpage writeback correctly Qu Wenruo
2024-05-21 7:13 ` Naohiro Aota
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=30371f39-18b1-4c3f-af31-b4927eab99a5@suse.com \
--to=wqu@suse.com \
--cc=Johannes.Thumshirn@wdc.com \
--cc=Naohiro.Aota@wdc.com \
--cc=josef@toxicpanda.com \
--cc=linux-btrfs@vger.kernel.org \
/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