* [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases
@ 2026-04-26 7:51 Qu Wenruo
2026-04-26 7:51 ` [PATCH 1/2] btrfs: enable cross-folio " Qu Wenruo
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Qu Wenruo @ 2026-04-26 7:51 UTC (permalink / raw)
To: linux-btrfs
Compressed data readahead is disabled for bs < ps cases, but it has
never taken large folios into the consideration.
And that unexpectedly enables compressed data readahead for large
folios, which should go through the same subpage routine.
This means for real bs < ps cases compressed data read is disabled, but
still enabled for bs == ps with large folios.
This small series will properly enable the compressed readahead for both
bs < ps and large folios cases, mostly by simply remove the unnecessary
checks.
Then since we're here, also update the function name and comments to
reflect that we're already using folio interface, not the old page
interface.
Qu Wenruo (2):
btrfs: enable cross-folio readahead for bs < ps and large folio cases
btrfs: refresh add_ra_bio_pages() to indicate it's using folios
fs/btrfs/compression.c | 67 +++++++++++++++---------------------------
1 file changed, 24 insertions(+), 43 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] btrfs: enable cross-folio readahead for bs < ps and large folio cases
2026-04-26 7:51 [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases Qu Wenruo
@ 2026-04-26 7:51 ` Qu Wenruo
2026-04-27 13:21 ` David Sterba
2026-04-26 7:51 ` [PATCH 2/2] btrfs: refresh add_ra_bio_pages() to indicate it's using folios Qu Wenruo
2026-04-27 13:38 ` [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases David Sterba
2 siblings, 1 reply; 8+ messages in thread
From: Qu Wenruo @ 2026-04-26 7:51 UTC (permalink / raw)
To: linux-btrfs
[BACKGROUND]
When bs < ps support was initially introduced, the compressed data
readahead was disabled as at that time the target page size was 64K, which
means a compressed data extent can span at most 3 64K pages (the head
and tail parts are not aligned to 64K), meaning the benefit is pretty
minimal.
[UNEXPECTED WORKING SITUATION]
But with the already merged large folio support, we're already enabling
readahead with subpage routine unintentionally, e.g:
0 4K 8K 12K 16K
| Folio 0 | Folio 8K |
|<----- Compressed data ------->|
We have 2 8K sized folios, all backed by a single compressed data.
In that case add_ra_bio_pages() will continue to add folio 8K into the
read bio, as the condition to skip is only (bs < ps), not taking the
newer large folio support into consideration at all.
So for folio 8K, it is added to the read bio, but without subpage lock
bitmap populated.
Then at end_bbio_data_read(), folio 0 has proper locked bitmap set, but
folio 8K does not.
This inconsistency is handled by the extra safety net at
btrfs_subpage_end_and_test_lock() where if a folio has no @nr_locked, it
will just be unlocked without touching the locked bitmap.
[ENHANCEMENT]
Make add_ra_bio_pages() support bs < ps and large folio cases, by
removing the check and calling btrfs_folio_set_lock() unconditionally.
This won't make any difference on 4K page sized systems with large
folios, as the readahead is already working, although unexpectedly.
But this will enable true compressed data readahead for bs < ps cases
properly.
Please note that such readahead will only work if the compressed extent is
crossing folio boundaries, which is also the existing limit.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/compression.c | 31 ++++++-------------------------
1 file changed, 6 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index c5783ac1b646..09729728624b 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -358,10 +358,7 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
* Add extra pages in the same compressed file extent so that we don't need to
* re-read the same extent again and again.
*
- * NOTE: this won't work well for subpage, as for subpage read, we lock the
- * full page then submit bio for each compressed/regular extents.
- *
- * This means, if we have several sectors in the same page points to the same
+ * If we have several sectors in the same page points to the same
* on-disk compressed data, we will re-read the same extent many times and
* this function can only help for the next page.
*/
@@ -391,16 +388,6 @@ static noinline int add_ra_bio_pages(struct inode *inode,
if (isize == 0)
return 0;
- /*
- * For current subpage support, we only support 64K page size,
- * which means maximum compressed extent size (128K) is just 2x page
- * size.
- * This makes readahead less effective, so here disable readahead for
- * subpage for now, until full compressed write is supported.
- */
- if (fs_info->sectorsize < PAGE_SIZE)
- return 0;
-
/* For bs > ps cases, we don't support readahead for compressed folios for now. */
if (fs_info->block_min_order)
return 0;
@@ -442,8 +429,8 @@ static noinline int add_ra_bio_pages(struct inode *inode,
break;
/*
- * Jump to next page start as we already have page for
- * current offset.
+ * Jump to the next folio as we already have a folio for
+ * the current offset.
*/
cur += (folio_sz - offset);
continue;
@@ -455,7 +442,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
break;
if (filemap_add_folio(mapping, folio, pg_index, cache_gfp)) {
- /* There is already a page, skip to page end */
+ /* There is already a folio, skip to folio end */
cur += folio_size(folio);
folio_put(folio);
continue;
@@ -480,7 +467,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
read_unlock(&em_tree->lock);
/*
- * At this point, we have a locked page in the page cache for
+ * At this point, we have a locked folio in the page cache for
* these bytes in the file. But, we have to make sure they map
* to this compressed extent on disk.
*/
@@ -514,13 +501,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
folio_put(folio);
break;
}
- /*
- * If it's subpage, we also need to increase its
- * subpage::readers number, as at endio we will decrease
- * subpage::readers and to unlock the page.
- */
- if (fs_info->sectorsize < PAGE_SIZE)
- btrfs_folio_set_lock(fs_info, folio, cur, add_size);
+ btrfs_folio_set_lock(fs_info, folio, cur, add_size);
folio_put(folio);
cur += add_size;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] btrfs: refresh add_ra_bio_pages() to indicate it's using folios
2026-04-26 7:51 [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases Qu Wenruo
2026-04-26 7:51 ` [PATCH 1/2] btrfs: enable cross-folio " Qu Wenruo
@ 2026-04-26 7:51 ` Qu Wenruo
2026-04-27 13:37 ` David Sterba
2026-04-27 13:38 ` [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases David Sterba
2 siblings, 1 reply; 8+ messages in thread
From: Qu Wenruo @ 2026-04-26 7:51 UTC (permalink / raw)
To: linux-btrfs
The function add_ra_bio_folios() has been utilizing folio interfaces
since c808c1dcb1b2 ("btrfs: convert add_ra_bio_pages() to use only
folios"), but we are still referring to "pages" inside the function name
and all comments.
Furthermore, such folio/page mixing can even be confusing, e.g. the
variable @page_end is very confusing as we're not really referring to
the end of the page, but the end of the folio, especially when we
already have large folio support.
Enhance that function by:
- Rename "page" to "folio" to avoid confusion
- Skip to the folio end if there is already a folio in the page cache
The existing skip is:
cur += folio_size(folio);
This is incorrect if @cur is not folio size aligned, and can be
common with large folio support.
Thankfully this is not going to cause any real bugs, but at most will
skip some blocks that can be added to readahead.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/compression.c | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 09729728624b..8ee0a4117d62 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -355,18 +355,18 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
}
/*
- * Add extra pages in the same compressed file extent so that we don't need to
+ * Add extra folios in the same compressed file extent so that we don't need to
* re-read the same extent again and again.
*
- * If we have several sectors in the same page points to the same
+ * If we have several blocks in the same folio pointing to the same
* on-disk compressed data, we will re-read the same extent many times and
- * this function can only help for the next page.
+ * this function can only help for the next folio(s).
*/
-static noinline int add_ra_bio_pages(struct inode *inode,
- u64 compressed_end,
- struct compressed_bio *cb,
- int *memstall, unsigned long *pflags,
- bool direct_reclaim)
+static noinline int add_ra_bio_folios(struct inode *inode,
+ u64 compressed_end,
+ struct compressed_bio *cb,
+ int *memstall, unsigned long *pflags,
+ bool direct_reclaim)
{
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
pgoff_t end_index;
@@ -396,7 +396,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
/*
* Avoid direct reclaim when the caller does not allow it. Since
- * add_ra_bio_pages() is always speculative, suppress allocation warnings
+ * add_ra_bio_folios() is always speculative, suppress allocation warnings
* in either case.
*/
if (!direct_reclaim) {
@@ -408,7 +408,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
}
while (cur < compressed_end) {
- pgoff_t page_end;
+ u64 folio_end;
pgoff_t pg_index = cur >> PAGE_SHIFT;
u32 add_size;
@@ -442,8 +442,8 @@ static noinline int add_ra_bio_pages(struct inode *inode,
break;
if (filemap_add_folio(mapping, folio, pg_index, cache_gfp)) {
- /* There is already a folio, skip to folio end */
- cur += folio_size(folio);
+ /* There is already a folio, skip to the folio end */
+ cur += folio_size(folio) - offset_in_folio(folio, cur);
folio_put(folio);
continue;
}
@@ -460,10 +460,10 @@ static noinline int add_ra_bio_pages(struct inode *inode,
break;
}
- page_end = (pg_index << PAGE_SHIFT) + folio_size(folio) - 1;
- btrfs_lock_extent(tree, cur, page_end, NULL);
+ folio_end = folio_next_pos(folio) - 1;
+ btrfs_lock_extent(tree, cur, folio_end, NULL);
read_lock(&em_tree->lock);
- em = btrfs_lookup_extent_mapping(em_tree, cur, page_end + 1 - cur);
+ em = btrfs_lookup_extent_mapping(em_tree, cur, folio_end + 1 - cur);
read_unlock(&em_tree->lock);
/*
@@ -476,14 +476,14 @@ static noinline int add_ra_bio_pages(struct inode *inode,
(btrfs_extent_map_block_start(em) >> SECTOR_SHIFT) !=
orig_bio->bi_iter.bi_sector) {
btrfs_free_extent_map(em);
- btrfs_unlock_extent(tree, cur, page_end, NULL);
+ btrfs_unlock_extent(tree, cur, folio_end, NULL);
folio_unlock(folio);
folio_put(folio);
break;
}
- add_size = min(btrfs_extent_map_end(em), page_end + 1) - cur;
+ add_size = min(btrfs_extent_map_end(em), folio_end + 1) - cur;
btrfs_free_extent_map(em);
- btrfs_unlock_extent(tree, cur, page_end, NULL);
+ btrfs_unlock_extent(tree, cur, folio_end, NULL);
if (folio_contains(folio, end_index)) {
size_t zero_offset = offset_in_folio(folio, isize);
@@ -592,8 +592,8 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
}
ASSERT(cb->bbio.bio.bi_iter.bi_size == compressed_len);
- add_ra_bio_pages(&inode->vfs_inode, em_start + em_len, cb, &memstall,
- &pflags, !(bbio->bio.bi_opf & REQ_RAHEAD));
+ add_ra_bio_folios(&inode->vfs_inode, em_start + em_len, cb, &memstall,
+ &pflags, !(bbio->bio.bi_opf & REQ_RAHEAD));
cb->len = bbio->bio.bi_iter.bi_size;
cb->bbio.bio.bi_iter.bi_sector = bbio->bio.bi_iter.bi_sector;
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] btrfs: enable cross-folio readahead for bs < ps and large folio cases
2026-04-26 7:51 ` [PATCH 1/2] btrfs: enable cross-folio " Qu Wenruo
@ 2026-04-27 13:21 ` David Sterba
2026-04-27 21:54 ` Qu Wenruo
0 siblings, 1 reply; 8+ messages in thread
From: David Sterba @ 2026-04-27 13:21 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs
On Sun, Apr 26, 2026 at 05:21:03PM +0930, Qu Wenruo wrote:
> --- a/fs/btrfs/compression.c
> +++ b/fs/btrfs/compression.c
> @@ -358,10 +358,7 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
> * Add extra pages in the same compressed file extent so that we don't need to
> * re-read the same extent again and again.
> *
> - * NOTE: this won't work well for subpage, as for subpage read, we lock the
> - * full page then submit bio for each compressed/regular extents.
> - *
> - * This means, if we have several sectors in the same page points to the same
> + * If we have several sectors in the same page points to the same
The sentence seems to be missing some words, or I don't understand
what's the meaning here.
> * on-disk compressed data, we will re-read the same extent many times and
> * this function can only help for the next page.
> */
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] btrfs: refresh add_ra_bio_pages() to indicate it's using folios
2026-04-26 7:51 ` [PATCH 2/2] btrfs: refresh add_ra_bio_pages() to indicate it's using folios Qu Wenruo
@ 2026-04-27 13:37 ` David Sterba
0 siblings, 0 replies; 8+ messages in thread
From: David Sterba @ 2026-04-27 13:37 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs
On Sun, Apr 26, 2026 at 05:21:04PM +0930, Qu Wenruo wrote:
> The function add_ra_bio_folios() has been utilizing folio interfaces
> since c808c1dcb1b2 ("btrfs: convert add_ra_bio_pages() to use only
> folios"), but we are still referring to "pages" inside the function name
> and all comments.
>
> Furthermore, such folio/page mixing can even be confusing, e.g. the
> variable @page_end is very confusing as we're not really referring to
> the end of the page, but the end of the folio, especially when we
> already have large folio support.
There are still too many mentions of 'page' so it will take time to
clean them up.
> Enhance that function by:
>
> - Rename "page" to "folio" to avoid confusion
>
> - Skip to the folio end if there is already a folio in the page cache
> The existing skip is:
>
> cur += folio_size(folio);
>
> This is incorrect if @cur is not folio size aligned, and can be
> common with large folio support.
>
> Thankfully this is not going to cause any real bugs, but at most will
> skip some blocks that can be added to readahead.
>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> fs/btrfs/compression.c | 40 ++++++++++++++++++++--------------------
> 1 file changed, 20 insertions(+), 20 deletions(-)
>
> diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
> index 09729728624b..8ee0a4117d62 100644
> --- a/fs/btrfs/compression.c
> +++ b/fs/btrfs/compression.c
> @@ -355,18 +355,18 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
> }
>
> /*
> - * Add extra pages in the same compressed file extent so that we don't need to
> + * Add extra folios in the same compressed file extent so that we don't need to
> * re-read the same extent again and again.
> *
> - * If we have several sectors in the same page points to the same
> + * If we have several blocks in the same folio pointing to the same
> * on-disk compressed data, we will re-read the same extent many times and
> - * this function can only help for the next page.
> + * this function can only help for the next folio(s).
> */
> -static noinline int add_ra_bio_pages(struct inode *inode,
> - u64 compressed_end,
> - struct compressed_bio *cb,
> - int *memstall, unsigned long *pflags,
> - bool direct_reclaim)
> +static noinline int add_ra_bio_folios(struct inode *inode,
> + u64 compressed_end,
> + struct compressed_bio *cb,
> + int *memstall, unsigned long *pflags,
the pflags are not for a 'page' but for the psi_memstall, this got me
confused for a second if it's not remant to be renamed as well.
> if (filemap_add_folio(mapping, folio, pg_index, cache_gfp)) {
> - /* There is already a folio, skip to folio end */
> - cur += folio_size(folio);
> + /* There is already a folio, skip to the folio end */
> + cur += folio_size(folio) - offset_in_folio(folio, cur);
> folio_put(folio);
> continue;
> }
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases
2026-04-26 7:51 [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases Qu Wenruo
2026-04-26 7:51 ` [PATCH 1/2] btrfs: enable cross-folio " Qu Wenruo
2026-04-26 7:51 ` [PATCH 2/2] btrfs: refresh add_ra_bio_pages() to indicate it's using folios Qu Wenruo
@ 2026-04-27 13:38 ` David Sterba
2 siblings, 0 replies; 8+ messages in thread
From: David Sterba @ 2026-04-27 13:38 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs
On Sun, Apr 26, 2026 at 05:21:02PM +0930, Qu Wenruo wrote:
> Compressed data readahead is disabled for bs < ps cases, but it has
> never taken large folios into the consideration.
>
> And that unexpectedly enables compressed data readahead for large
> folios, which should go through the same subpage routine.
>
> This means for real bs < ps cases compressed data read is disabled, but
> still enabled for bs == ps with large folios.
>
> This small series will properly enable the compressed readahead for both
> bs < ps and large folios cases, mostly by simply remove the unnecessary
> checks.
>
> Then since we're here, also update the function name and comments to
> reflect that we're already using folio interface, not the old page
> interface.
>
> Qu Wenruo (2):
> btrfs: enable cross-folio readahead for bs < ps and large folio cases
> btrfs: refresh add_ra_bio_pages() to indicate it's using folios
Please add it to for-next, thanks.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] btrfs: enable cross-folio readahead for bs < ps and large folio cases
2026-04-27 13:21 ` David Sterba
@ 2026-04-27 21:54 ` Qu Wenruo
2026-04-28 3:53 ` David Sterba
0 siblings, 1 reply; 8+ messages in thread
From: Qu Wenruo @ 2026-04-27 21:54 UTC (permalink / raw)
To: dsterba, Qu Wenruo; +Cc: linux-btrfs
在 2026/4/27 22:51, David Sterba 写道:
> On Sun, Apr 26, 2026 at 05:21:03PM +0930, Qu Wenruo wrote:
>> --- a/fs/btrfs/compression.c
>> +++ b/fs/btrfs/compression.c
>> @@ -358,10 +358,7 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
>> * Add extra pages in the same compressed file extent so that we don't need to
>> * re-read the same extent again and again.
>> *
>> - * NOTE: this won't work well for subpage, as for subpage read, we lock the
>> - * full page then submit bio for each compressed/regular extents.
>> - *
>> - * This means, if we have several sectors in the same page points to the same
>> + * If we have several sectors in the same page points to the same
>
> The sentence seems to be missing some words, or I don't understand
> what's the meaning here.
This means the situation like the following:
| Folio range |
| Ext A| | Ext B|
Where Ext A and B are backed by the same compressed extent.
In that case, if we're reading Ext A, the readahead won't work for Ext B.
Thanks,
Qu
>
>> * on-disk compressed data, we will re-read the same extent many times and
>> * this function can only help for the next page.
>> */
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] btrfs: enable cross-folio readahead for bs < ps and large folio cases
2026-04-27 21:54 ` Qu Wenruo
@ 2026-04-28 3:53 ` David Sterba
0 siblings, 0 replies; 8+ messages in thread
From: David Sterba @ 2026-04-28 3:53 UTC (permalink / raw)
To: Qu Wenruo; +Cc: Qu Wenruo, linux-btrfs
On Tue, Apr 28, 2026 at 07:24:00AM +0930, Qu Wenruo wrote:
>
>
> 在 2026/4/27 22:51, David Sterba 写道:
> > On Sun, Apr 26, 2026 at 05:21:03PM +0930, Qu Wenruo wrote:
> >> --- a/fs/btrfs/compression.c
> >> +++ b/fs/btrfs/compression.c
> >> @@ -358,10 +358,7 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
> >> * Add extra pages in the same compressed file extent so that we don't need to
> >> * re-read the same extent again and again.
> >> *
> >> - * NOTE: this won't work well for subpage, as for subpage read, we lock the
> >> - * full page then submit bio for each compressed/regular extents.
> >> - *
> >> - * This means, if we have several sectors in the same page points to the same
> >> + * If we have several sectors in the same page points to the same
> >
> > The sentence seems to be missing some words, or I don't understand
> > what's the meaning here.
>
> This means the situation like the following:
>
> | Folio range |
> | Ext A| | Ext B|
>
> Where Ext A and B are backed by the same compressed extent.
>
> In that case, if we're reading Ext A, the readahead won't work for Ext B.
Ok, so it should read "If we have several sectors inthe same page
that points to the same ...".
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-04-28 3:53 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-26 7:51 [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases Qu Wenruo
2026-04-26 7:51 ` [PATCH 1/2] btrfs: enable cross-folio " Qu Wenruo
2026-04-27 13:21 ` David Sterba
2026-04-27 21:54 ` Qu Wenruo
2026-04-28 3:53 ` David Sterba
2026-04-26 7:51 ` [PATCH 2/2] btrfs: refresh add_ra_bio_pages() to indicate it's using folios Qu Wenruo
2026-04-27 13:37 ` David Sterba
2026-04-27 13:38 ` [PATCH 0/2] btrfs: properly enable compressed readahead for bs < ps and large folio cases David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox