* [PATCH 0/5] btrfs: prepare for larger folios support
@ 2025-02-20 9:22 Qu Wenruo
2025-02-20 9:22 ` [PATCH 1/5] btrfs: prepare subpage.c " Qu Wenruo
` (5 more replies)
0 siblings, 6 replies; 17+ messages in thread
From: Qu Wenruo @ 2025-02-20 9:22 UTC (permalink / raw)
To: linux-btrfs
This means:
- Our subpage routine should check against the folio size other than
PAGE_SIZE
- Make functions handling filemap folios to use folio_size() other than
PAGE_SIZE
The most common paths are:
* Buffered reads/writes
* Uncompressed folio writeback
Already handled pretty well
* Compressed read
* Compressed write
To take full advantage of larger folios, we should use folio_iter
other than bvec_iter.
This will be a dedicated patchset, and the existing bvec_iter can
still handle larger folios.
Internal usages can still use page sized folios, or even pages,
including:
* Encoded reads/writes
* Compressed folios
* RAID56 internal pages
* Scrub internal pages
This patchset will handle the above mentioned points by:
- Prepare the subpage routine to handle larger folios
This will introduce a small overhead, as all checks are against folio
sizes, even on x86_64 we can no longer skip subpage completely.
This is done in the first patch.
- Convert straightforward PAGE_SIZE users to use folio_size()
This is done in the remaining patches.
Currently this patchset is not a exhaustive conversion, I'm pretty sure
there are other complex situations which can cause problems.
Those problems can only be exposed and fixed after switching on the
experimental larger folios support later.
Qu Wenruo (5):
btrfs: prepare subpage.c for larger folios support
btrfs: remove the PAGE_SIZE usage inside inline extent reads
btrfs: prepare btrfs_launcher_folio() for larger folios support
btrfs: prepare extent_io.c for future larger folio support
btrfs: prepare btrfs_page_mkwrite() for larger folios
fs/btrfs/extent_io.c | 50 +++++++++++++++++++++++++-------------------
fs/btrfs/file.c | 19 +++++++++--------
fs/btrfs/inode.c | 8 +++----
fs/btrfs/subpage.c | 36 +++++++++++++++----------------
fs/btrfs/subpage.h | 24 ++++++++-------------
5 files changed, 69 insertions(+), 68 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/5] btrfs: prepare subpage.c for larger folios support
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
@ 2025-02-20 9:22 ` Qu Wenruo
2025-02-21 12:06 ` Johannes Thumshirn
2025-02-20 9:22 ` [PATCH 2/5] btrfs: remove the PAGE_SIZE usage inside inline extent reads Qu Wenruo
` (4 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Qu Wenruo @ 2025-02-20 9:22 UTC (permalink / raw)
To: linux-btrfs
For the future of larger folio support, even if block size == page size,
we may still hit a larger folio and need to attach a subpage structure to
that larger folio.
In that case we can no longer assume we need to go subpage routine only
when block size < page size, but take folio size into the consideration.
Prepare for such future by:
- Use folio_size() instead of PAGE_SIZE
- Make btrfs_alloc_subpage() to handle different folio sizes
- Make btrfs_is_subpage() to do the check based on the folio
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/extent_io.c | 17 +++++++++--------
fs/btrfs/inode.c | 2 +-
fs/btrfs/subpage.c | 36 ++++++++++++++++++------------------
fs/btrfs/subpage.h | 24 +++++++++---------------
4 files changed, 37 insertions(+), 42 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index c023ea514f64..e1efb6419601 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -432,7 +432,7 @@ static void end_folio_read(struct folio *folio, bool uptodate, u64 start, u32 le
else
btrfs_folio_clear_uptodate(fs_info, folio, start, len);
- if (!btrfs_is_subpage(fs_info, folio->mapping))
+ if (!btrfs_is_subpage(fs_info, folio))
folio_unlock(folio);
else
btrfs_folio_end_lock(fs_info, folio, start, len);
@@ -488,7 +488,7 @@ static void end_bbio_data_write(struct btrfs_bio *bbio)
static void begin_folio_read(struct btrfs_fs_info *fs_info, struct folio *folio)
{
ASSERT(folio_test_locked(folio));
- if (!btrfs_is_subpage(fs_info, folio->mapping))
+ if (!btrfs_is_subpage(fs_info, folio))
return;
ASSERT(folio_test_private(folio));
@@ -870,7 +870,7 @@ int set_folio_extent_mapped(struct folio *folio)
fs_info = folio_to_fs_info(folio);
- if (btrfs_is_subpage(fs_info, folio->mapping))
+ if (btrfs_is_subpage(fs_info, folio))
return btrfs_attach_subpage(fs_info, folio, BTRFS_SUBPAGE_DATA);
folio_attach_private(folio, (void *)EXTENT_FOLIO_PRIVATE);
@@ -887,7 +887,7 @@ void clear_folio_extent_mapped(struct folio *folio)
return;
fs_info = folio_to_fs_info(folio);
- if (btrfs_is_subpage(fs_info, folio->mapping))
+ if (btrfs_is_subpage(fs_info, folio))
return btrfs_detach_subpage(fs_info, folio, BTRFS_SUBPAGE_DATA);
folio_detach_private(folio);
@@ -1329,7 +1329,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
{
struct btrfs_fs_info *fs_info = inode_to_fs_info(&inode->vfs_inode);
struct writeback_control *wbc = bio_ctrl->wbc;
- const bool is_subpage = btrfs_is_subpage(fs_info, folio->mapping);
+ const bool is_subpage = btrfs_is_subpage(fs_info, folio);
const u64 page_start = folio_pos(folio);
const u64 page_end = page_start + folio_size(folio) - 1;
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
@@ -1357,7 +1357,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
int bit;
/* Save the dirty bitmap as our submission bitmap will be a subset of it. */
- if (btrfs_is_subpage(fs_info, inode->vfs_inode.i_mapping)) {
+ if (is_subpage) {
ASSERT(blocks_per_folio > 1);
btrfs_get_subpage_dirty_bitmap(fs_info, folio, &bio_ctrl->submit_bitmap);
} else {
@@ -2387,7 +2387,7 @@ static int extent_write_cache_pages(struct address_space *mapping,
* regular submission.
*/
if (wbc->sync_mode != WB_SYNC_NONE ||
- btrfs_is_subpage(inode_to_fs_info(inode), mapping)) {
+ btrfs_is_subpage(inode_to_fs_info(inode), folio)) {
if (folio_test_writeback(folio))
submit_write_bio(bio_ctrl, 0);
folio_wait_writeback(folio);
@@ -3245,7 +3245,8 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
* manually if we exit earlier.
*/
if (btrfs_meta_is_subpage(fs_info)) {
- prealloc = btrfs_alloc_subpage(fs_info, BTRFS_SUBPAGE_METADATA);
+ prealloc = btrfs_alloc_subpage(fs_info, PAGE_SIZE,
+ BTRFS_SUBPAGE_METADATA);
if (IS_ERR(prealloc)) {
ret = PTR_ERR(prealloc);
goto out;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 7796e81dbb9d..3af74f3c5d75 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7246,7 +7246,7 @@ static void wait_subpage_spinlock(struct folio *folio)
struct btrfs_fs_info *fs_info = folio_to_fs_info(folio);
struct btrfs_subpage *subpage;
- if (!btrfs_is_subpage(fs_info, folio->mapping))
+ if (!btrfs_is_subpage(fs_info, folio))
return;
ASSERT(folio_test_private(folio) && folio_get_private(folio));
diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c
index 4d7600e14286..afaa1f381a74 100644
--- a/fs/btrfs/subpage.c
+++ b/fs/btrfs/subpage.c
@@ -84,10 +84,10 @@ int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
return 0;
if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
return 0;
- if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio->mapping))
+ if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio))
return 0;
- subpage = btrfs_alloc_subpage(fs_info, type);
+ subpage = btrfs_alloc_subpage(fs_info, folio_size(folio), type);
if (IS_ERR(subpage))
return PTR_ERR(subpage);
@@ -105,7 +105,7 @@ void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *fol
return;
if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
return;
- if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio->mapping))
+ if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio))
return;
subpage = folio_detach_private(folio);
@@ -114,16 +114,16 @@ void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *fol
}
struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
- enum btrfs_subpage_type type)
+ size_t fsize, enum btrfs_subpage_type type)
{
struct btrfs_subpage *ret;
unsigned int real_size;
- ASSERT(fs_info->sectorsize < PAGE_SIZE);
+ ASSERT(fs_info->sectorsize < fsize);
real_size = struct_size(ret, bitmaps,
BITS_TO_LONGS(btrfs_bitmap_nr_max *
- (PAGE_SIZE >> fs_info->sectorsize_bits)));
+ (fsize >> fs_info->sectorsize_bits)));
ret = kzalloc(real_size, GFP_NOFS);
if (!ret)
return ERR_PTR(-ENOMEM);
@@ -195,7 +195,7 @@ static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
*/
if (folio->mapping)
ASSERT(folio_pos(folio) <= start &&
- start + len <= folio_pos(folio) + PAGE_SIZE);
+ start + len <= folio_pos(folio) + folio_size(folio));
}
#define subpage_calc_start_bit(fs_info, folio, name, start, len) \
@@ -224,7 +224,7 @@ static void btrfs_subpage_clamp_range(struct folio *folio, u64 *start, u32 *len)
if (folio_pos(folio) >= orig_start + orig_len)
*len = 0;
else
- *len = min_t(u64, folio_pos(folio) + PAGE_SIZE,
+ *len = min_t(u64, folio_pos(folio) + folio_size(folio),
orig_start + orig_len) - *start;
}
@@ -287,7 +287,7 @@ void btrfs_folio_end_lock(const struct btrfs_fs_info *fs_info,
ASSERT(folio_test_locked(folio));
- if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio->mapping)) {
+ if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio)) {
folio_unlock(folio);
return;
}
@@ -321,7 +321,7 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
int cleared = 0;
int bit;
- if (!btrfs_is_subpage(fs_info, folio->mapping)) {
+ if (!btrfs_is_subpage(fs_info, folio)) {
folio_unlock(folio);
return;
}
@@ -573,7 +573,7 @@ void btrfs_folio_set_##name(const struct btrfs_fs_info *fs_info, \
struct folio *folio, u64 start, u32 len) \
{ \
if (unlikely(!fs_info) || \
- !btrfs_is_subpage(fs_info, folio->mapping)) { \
+ !btrfs_is_subpage(fs_info, folio)) { \
folio_set_func(folio); \
return; \
} \
@@ -583,7 +583,7 @@ void btrfs_folio_clear_##name(const struct btrfs_fs_info *fs_info, \
struct folio *folio, u64 start, u32 len) \
{ \
if (unlikely(!fs_info) || \
- !btrfs_is_subpage(fs_info, folio->mapping)) { \
+ !btrfs_is_subpage(fs_info, folio)) { \
folio_clear_func(folio); \
return; \
} \
@@ -593,7 +593,7 @@ bool btrfs_folio_test_##name(const struct btrfs_fs_info *fs_info, \
struct folio *folio, u64 start, u32 len) \
{ \
if (unlikely(!fs_info) || \
- !btrfs_is_subpage(fs_info, folio->mapping)) \
+ !btrfs_is_subpage(fs_info, folio)) \
return folio_test_func(folio); \
return btrfs_subpage_test_##name(fs_info, folio, start, len); \
} \
@@ -601,7 +601,7 @@ void btrfs_folio_clamp_set_##name(const struct btrfs_fs_info *fs_info, \
struct folio *folio, u64 start, u32 len) \
{ \
if (unlikely(!fs_info) || \
- !btrfs_is_subpage(fs_info, folio->mapping)) { \
+ !btrfs_is_subpage(fs_info, folio)) { \
folio_set_func(folio); \
return; \
} \
@@ -612,7 +612,7 @@ void btrfs_folio_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \
struct folio *folio, u64 start, u32 len) \
{ \
if (unlikely(!fs_info) || \
- !btrfs_is_subpage(fs_info, folio->mapping)) { \
+ !btrfs_is_subpage(fs_info, folio)) { \
folio_clear_func(folio); \
return; \
} \
@@ -623,7 +623,7 @@ bool btrfs_folio_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
struct folio *folio, u64 start, u32 len) \
{ \
if (unlikely(!fs_info) || \
- !btrfs_is_subpage(fs_info, folio->mapping)) \
+ !btrfs_is_subpage(fs_info, folio)) \
return folio_test_func(folio); \
btrfs_subpage_clamp_range(folio, &start, &len); \
return btrfs_subpage_test_##name(fs_info, folio, start, len); \
@@ -704,7 +704,7 @@ void btrfs_folio_assert_not_dirty(const struct btrfs_fs_info *fs_info,
if (!IS_ENABLED(CONFIG_BTRFS_ASSERT))
return;
- if (!btrfs_is_subpage(fs_info, folio->mapping)) {
+ if (!btrfs_is_subpage(fs_info, folio)) {
ASSERT(!folio_test_dirty(folio));
return;
}
@@ -739,7 +739,7 @@ void btrfs_folio_set_lock(const struct btrfs_fs_info *fs_info,
int ret;
ASSERT(folio_test_locked(folio));
- if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio->mapping))
+ if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio))
return;
subpage = folio_get_private(folio);
diff --git a/fs/btrfs/subpage.h b/fs/btrfs/subpage.h
index e10a1d308f32..f8d1efa1a227 100644
--- a/fs/btrfs/subpage.h
+++ b/fs/btrfs/subpage.h
@@ -84,27 +84,21 @@ static inline bool btrfs_meta_is_subpage(const struct btrfs_fs_info *fs_info)
{
return fs_info->nodesize < PAGE_SIZE;
}
-static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
- struct address_space *mapping)
-{
- if (mapping && mapping->host)
- ASSERT(is_data_inode(BTRFS_I(mapping->host)));
- return fs_info->sectorsize < PAGE_SIZE;
-}
#else
static inline bool btrfs_meta_is_subpage(const struct btrfs_fs_info *fs_info)
{
return false;
}
-static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
- struct address_space *mapping)
-{
- if (mapping && mapping->host)
- ASSERT(is_data_inode(BTRFS_I(mapping->host)));
- return false;
-}
#endif
+static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
+ struct folio *folio)
+{
+ if (folio_mapped(folio) && folio->mapping && folio->mapping->host)
+ ASSERT(is_data_inode(BTRFS_I(folio->mapping->host)));
+ return fs_info->sectorsize < folio_size(folio);
+}
+
int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
struct folio *folio, enum btrfs_subpage_type type);
void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio,
@@ -112,7 +106,7 @@ void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *fol
/* Allocate additional data where page represents more than one sector */
struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
- enum btrfs_subpage_type type);
+ size_t fsize, enum btrfs_subpage_type type);
void btrfs_free_subpage(struct btrfs_subpage *subpage);
void btrfs_folio_inc_eb_refs(const struct btrfs_fs_info *fs_info, struct folio *folio);
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/5] btrfs: remove the PAGE_SIZE usage inside inline extent reads
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
2025-02-20 9:22 ` [PATCH 1/5] btrfs: prepare subpage.c " Qu Wenruo
@ 2025-02-20 9:22 ` Qu Wenruo
2025-02-21 11:37 ` Johannes Thumshirn
2025-02-20 9:22 ` [PATCH 3/5] btrfs: prepare btrfs_launcher_folio() for larger folios support Qu Wenruo
` (3 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Qu Wenruo @ 2025-02-20 9:22 UTC (permalink / raw)
To: linux-btrfs
The inline extent ram size should never exceed btrfs block size, there
is no need to clamp the size against PAGE_SIZE.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/inode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3af74f3c5d75..d9ca92d1b927 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6784,7 +6784,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
read_extent_buffer(leaf, tmp, ptr, inline_size);
- max_size = min_t(unsigned long, PAGE_SIZE, max_size);
+ max_size = min_t(unsigned long, sectorsize, max_size);
ret = btrfs_decompress(compress_type, tmp, folio, 0, inline_size,
max_size);
@@ -6820,7 +6820,7 @@ static int read_inline_extent(struct btrfs_fs_info *fs_info,
if (btrfs_file_extent_compression(path->nodes[0], fi) != BTRFS_COMPRESS_NONE)
return uncompress_inline(path, folio, fi);
- copy_size = min_t(u64, PAGE_SIZE,
+ copy_size = min_t(u64, sectorsize,
btrfs_file_extent_ram_bytes(path->nodes[0], fi));
kaddr = kmap_local_folio(folio, 0);
read_extent_buffer(path->nodes[0], kaddr,
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/5] btrfs: prepare btrfs_launcher_folio() for larger folios support
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
2025-02-20 9:22 ` [PATCH 1/5] btrfs: prepare subpage.c " Qu Wenruo
2025-02-20 9:22 ` [PATCH 2/5] btrfs: remove the PAGE_SIZE usage inside inline extent reads Qu Wenruo
@ 2025-02-20 9:22 ` Qu Wenruo
2025-02-21 12:08 ` Johannes Thumshirn
2025-02-20 9:22 ` [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support Qu Wenruo
` (2 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Qu Wenruo @ 2025-02-20 9:22 UTC (permalink / raw)
To: linux-btrfs
That function is only calling btrfs_qgroup_free_data(), which doesn't
care the size of the folio.
Just replace the fixed PAGE_SIZE with folio_size().
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/inode.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d9ca92d1b927..c88aa961af51 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7270,7 +7270,7 @@ static void wait_subpage_spinlock(struct folio *folio)
static int btrfs_launder_folio(struct folio *folio)
{
return btrfs_qgroup_free_data(folio_to_inode(folio), NULL, folio_pos(folio),
- PAGE_SIZE, NULL);
+ folio_size(folio), NULL);
}
static bool __btrfs_release_folio(struct folio *folio, gfp_t gfp_flags)
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
` (2 preceding siblings ...)
2025-02-20 9:22 ` [PATCH 3/5] btrfs: prepare btrfs_launcher_folio() for larger folios support Qu Wenruo
@ 2025-02-20 9:22 ` Qu Wenruo
2025-02-21 12:12 ` Johannes Thumshirn
2025-02-25 18:41 ` Nathan Chancellor
2025-02-20 9:22 ` [PATCH 5/5] btrfs: prepare btrfs_page_mkwrite() for larger folios Qu Wenruo
2025-02-21 11:23 ` [PATCH 0/5] btrfs: prepare for larger folios support Johannes Thumshirn
5 siblings, 2 replies; 17+ messages in thread
From: Qu Wenruo @ 2025-02-20 9:22 UTC (permalink / raw)
To: linux-btrfs
When we're handling folios from filemap, we can no longer assume all
folios are page sized.
Thus for call sites assuming the folio is page sized, change the
PAGE_SIZE usage to folio_size() instead.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/extent_io.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index e1efb6419601..88bac9a32919 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -425,7 +425,7 @@ static void end_folio_read(struct folio *folio, bool uptodate, u64 start, u32 le
struct btrfs_fs_info *fs_info = folio_to_fs_info(folio);
ASSERT(folio_pos(folio) <= start &&
- start + len <= folio_pos(folio) + PAGE_SIZE);
+ start + len <= folio_pos(folio) + folio_size(folio));
if (uptodate && btrfs_verify_folio(folio, start, len))
btrfs_folio_set_uptodate(fs_info, folio, start, len);
@@ -492,7 +492,7 @@ static void begin_folio_read(struct btrfs_fs_info *fs_info, struct folio *folio)
return;
ASSERT(folio_test_private(folio));
- btrfs_folio_set_lock(fs_info, folio, folio_pos(folio), PAGE_SIZE);
+ btrfs_folio_set_lock(fs_info, folio, folio_pos(folio), folio_size(folio));
}
/*
@@ -753,7 +753,7 @@ static void submit_extent_folio(struct btrfs_bio_ctrl *bio_ctrl,
{
struct btrfs_inode *inode = folio_to_inode(folio);
- ASSERT(pg_offset + size <= PAGE_SIZE);
+ ASSERT(pg_offset + size <= folio_size(folio));
ASSERT(bio_ctrl->end_io_func);
if (bio_ctrl->bbio &&
@@ -935,7 +935,7 @@ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
struct inode *inode = folio->mapping->host;
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
u64 start = folio_pos(folio);
- const u64 end = start + PAGE_SIZE - 1;
+ const u64 end = start + folio_size(folio) - 1;
u64 cur = start;
u64 extent_offset;
u64 last_byte = i_size_read(inode);
@@ -1277,7 +1277,7 @@ static void set_delalloc_bitmap(struct folio *folio, unsigned long *delalloc_bit
unsigned int start_bit;
unsigned int nbits;
- ASSERT(start >= folio_start && start + len <= folio_start + PAGE_SIZE);
+ ASSERT(start >= folio_start && start + len <= folio_start + folio_size(folio));
start_bit = (start - folio_start) >> fs_info->sectorsize_bits;
nbits = len >> fs_info->sectorsize_bits;
ASSERT(bitmap_test_range_all_zero(delalloc_bitmap, start_bit, nbits));
@@ -1295,7 +1295,7 @@ static bool find_next_delalloc_bitmap(struct folio *folio,
unsigned int first_zero;
unsigned int first_set;
- ASSERT(start >= folio_start && start < folio_start + PAGE_SIZE);
+ ASSERT(start >= folio_start && start < folio_start + folio_size(folio));
start_bit = (start - folio_start) >> fs_info->sectorsize_bits;
first_set = find_next_bit(delalloc_bitmap, bitmap_size, start_bit);
@@ -1497,10 +1497,10 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
delalloc_end = page_end;
/*
* delalloc_end is already one less than the total length, so
- * we don't subtract one from PAGE_SIZE
+ * we don't subtract one from folio_size().
*/
delalloc_to_write +=
- DIV_ROUND_UP(delalloc_end + 1 - page_start, PAGE_SIZE);
+ DIV_ROUND_UP(delalloc_end + 1 - page_start, folio_size(folio));
/*
* If all ranges are submitted asynchronously, we just need to account
@@ -1737,7 +1737,7 @@ static int extent_writepage(struct folio *folio, struct btrfs_bio_ctrl *bio_ctrl
goto done;
ret = extent_writepage_io(inode, folio, folio_pos(folio),
- PAGE_SIZE, bio_ctrl, i_size);
+ folio_size(folio), bio_ctrl, i_size);
if (ret == 1)
return 0;
if (ret < 0)
@@ -2468,8 +2468,8 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(end + 1, sectorsize));
while (cur <= end) {
- u64 cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
- u32 cur_len = cur_end + 1 - cur;
+ u64 cur_end;
+ u32 cur_len;
struct folio *folio;
folio = filemap_get_folio(mapping, cur >> PAGE_SHIFT);
@@ -2479,13 +2479,18 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
* code is just in case, but shouldn't actually be run.
*/
if (IS_ERR(folio)) {
+ cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
+ cur_len = cur_end + 1 - cur;
btrfs_mark_ordered_io_finished(BTRFS_I(inode), NULL,
cur, cur_len, false);
mapping_set_error(mapping, PTR_ERR(folio));
- cur = cur_end + 1;
+ cur = cur_end;
continue;
}
+ cur_end = min(folio_pos(folio) + folio_size(folio) - 1, end);
+ cur_len = cur_end + 1 - cur;
+
ASSERT(folio_test_locked(folio));
if (pages_dirty && folio != locked_folio)
ASSERT(folio_test_dirty(folio));
@@ -2597,7 +2602,7 @@ static bool try_release_extent_state(struct extent_io_tree *tree,
struct folio *folio)
{
u64 start = folio_pos(folio);
- u64 end = start + PAGE_SIZE - 1;
+ u64 end = start + folio_size(folio) - 1;
bool ret;
if (test_range_bit_exists(tree, start, end, EXTENT_LOCKED)) {
@@ -2635,7 +2640,7 @@ static bool try_release_extent_state(struct extent_io_tree *tree,
bool try_release_extent_mapping(struct folio *folio, gfp_t mask)
{
u64 start = folio_pos(folio);
- u64 end = start + PAGE_SIZE - 1;
+ u64 end = start + folio_size(folio) - 1;
struct btrfs_inode *inode = folio_to_inode(folio);
struct extent_io_tree *io_tree = &inode->io_tree;
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 5/5] btrfs: prepare btrfs_page_mkwrite() for larger folios
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
` (3 preceding siblings ...)
2025-02-20 9:22 ` [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support Qu Wenruo
@ 2025-02-20 9:22 ` Qu Wenruo
2025-02-21 12:22 ` Johannes Thumshirn
2025-02-21 11:23 ` [PATCH 0/5] btrfs: prepare for larger folios support Johannes Thumshirn
5 siblings, 1 reply; 17+ messages in thread
From: Qu Wenruo @ 2025-02-20 9:22 UTC (permalink / raw)
To: linux-btrfs
This changes the assumption that the folio is always page sized.
(Although the ASSERT() for folio order is still kept as-is).
Just replace the PAGE_SIZE with folio_size().
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/file.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 05a70e50ed40..cebe5cb86a8c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1783,6 +1783,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
struct extent_changeset *data_reserved = NULL;
unsigned long zero_start;
loff_t size;
+ size_t fsize = folio_size(folio);
vm_fault_t ret;
int ret2;
int reserved = 0;
@@ -1793,7 +1794,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
ASSERT(folio_order(folio) == 0);
- reserved_space = PAGE_SIZE;
+ reserved_space = fsize;
sb_start_pagefault(inode->i_sb);
page_start = folio_pos(folio);
@@ -1847,7 +1848,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
* We can't set the delalloc bits if there are pending ordered
* extents. Drop our locks and wait for them to finish.
*/
- ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), page_start, PAGE_SIZE);
+ ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), page_start, fsize);
if (ordered) {
unlock_extent(io_tree, page_start, page_end, &cached_state);
folio_unlock(folio);
@@ -1859,11 +1860,11 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
if (folio->index == ((size - 1) >> PAGE_SHIFT)) {
reserved_space = round_up(size - page_start, fs_info->sectorsize);
- if (reserved_space < PAGE_SIZE) {
+ if (reserved_space < fsize) {
end = page_start + reserved_space - 1;
btrfs_delalloc_release_space(BTRFS_I(inode),
data_reserved, page_start,
- PAGE_SIZE - reserved_space, true);
+ fsize - reserved_space, true);
}
}
@@ -1890,12 +1891,12 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
if (page_start + folio_size(folio) > size)
zero_start = offset_in_folio(folio, size);
else
- zero_start = PAGE_SIZE;
+ zero_start = fsize;
- if (zero_start != PAGE_SIZE)
+ if (zero_start != fsize)
folio_zero_range(folio, zero_start, folio_size(folio) - zero_start);
- btrfs_folio_clear_checked(fs_info, folio, page_start, PAGE_SIZE);
+ btrfs_folio_clear_checked(fs_info, folio, page_start, fsize);
btrfs_folio_set_dirty(fs_info, folio, page_start, end + 1 - page_start);
btrfs_folio_set_uptodate(fs_info, folio, page_start, end + 1 - page_start);
@@ -1904,7 +1905,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
unlock_extent(io_tree, page_start, page_end, &cached_state);
up_read(&BTRFS_I(inode)->i_mmap_lock);
- btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), fsize);
sb_end_pagefault(inode->i_sb);
extent_changeset_free(data_reserved);
return VM_FAULT_LOCKED;
@@ -1913,7 +1914,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
folio_unlock(folio);
up_read(&BTRFS_I(inode)->i_mmap_lock);
out:
- btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), fsize);
btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved, page_start,
reserved_space, (ret != 0));
out_noreserve:
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 0/5] btrfs: prepare for larger folios support
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
` (4 preceding siblings ...)
2025-02-20 9:22 ` [PATCH 5/5] btrfs: prepare btrfs_page_mkwrite() for larger folios Qu Wenruo
@ 2025-02-21 11:23 ` Johannes Thumshirn
2025-02-21 12:34 ` Filipe Manana
2025-02-21 22:33 ` Qu Wenruo
5 siblings, 2 replies; 17+ messages in thread
From: Johannes Thumshirn @ 2025-02-21 11:23 UTC (permalink / raw)
To: WenRuo Qu, linux-btrfs@vger.kernel.org
On 20.02.25 10:26, Qu Wenruo wrote:
> Qu Wenruo (5):
> btrfs: prepare subpage.c for larger folios support
> btrfs: remove the PAGE_SIZE usage inside inline extent reads
> btrfs: prepare btrfs_launcher_folio() for larger folios support
> btrfs: prepare extent_io.c for future larger folio support
> btrfs: prepare btrfs_page_mkwrite() for larger folios
>
> fs/btrfs/extent_io.c | 50 +++++++++++++++++++++++++-------------------
> fs/btrfs/file.c | 19 +++++++++--------
> fs/btrfs/inode.c | 8 +++----
> fs/btrfs/subpage.c | 36 +++++++++++++++----------------
> fs/btrfs/subpage.h | 24 ++++++++-------------
> 5 files changed, 69 insertions(+), 68 deletions(-)
>
Hi Qu,
What am I doing wrong?
Applying: btrfs: prepare subpage.c for larger folios support
Applying: btrfs: remove the PAGE_SIZE usage inside inline extent reads
In file included from ./include/linux/kernel.h:28,
from ./include/linux/cpumask.h:11,
from ./include/linux/smp.h:13,
from ./include/linux/lockdep.h:14,
from ./include/linux/spinlock.h:63,
from ./include/linux/swait.h:7,
from ./include/linux/completion.h:12,
from ./include/linux/crypto.h:15,
from ./include/crypto/hash.h:12,
from fs/btrfs/inode.c:6:
fs/btrfs/inode.c: In function ‘uncompress_inline’:
fs/btrfs/inode.c:6807:41: error: ‘sectorsize’ undeclared (first use in
this function); did you mean ‘sector_t’?
6807 | max_size = min_t(unsigned long, sectorsize, max_size);
| ^~~~~~~~~~
./include/linux/minmax.h:86:23: note: in definition of macro
‘__cmp_once_unique’
86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
| ^
./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
| ^~~~~~~~~~
fs/btrfs/inode.c:6807:20: note: in expansion of macro ‘min_t’
6807 | max_size = min_t(unsigned long, sectorsize, max_size);
| ^~~~~
fs/btrfs/inode.c:6807:41: note: each undeclared identifier is reported
only once for each function it appears in
6807 | max_size = min_t(unsigned long, sectorsize, max_size);
| ^~~~~~~~~~
./include/linux/minmax.h:86:23: note: in definition of macro
‘__cmp_once_unique’
86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
| ^
./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
| ^~~~~~~~~~
fs/btrfs/inode.c:6807:20: note: in expansion of macro ‘min_t’
6807 | max_size = min_t(unsigned long, sectorsize, max_size);
| ^~~~~
fs/btrfs/inode.c: In function ‘read_inline_extent’:
fs/btrfs/inode.c:6841:32: error: ‘sectorsize’ undeclared (first use in
this function); did you mean ‘sector_t’?
6841 | copy_size = min_t(u64, sectorsize,
| ^~~~~~~~~~
./include/linux/minmax.h:86:23: note: in definition of macro
‘__cmp_once_unique’
86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
| ^
./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
| ^~~~~~~~~~
fs/btrfs/inode.c:6841:21: note: in expansion of macro ‘min_t’
6841 | copy_size = min_t(u64, sectorsize,
| ^~~~~
make[4]: *** [scripts/Makefile.build:207: fs/btrfs/inode.o] Error 1
make[3]: *** [scripts/Makefile.build:465: fs/btrfs] Error 2
make[2]: *** [scripts/Makefile.build:465: fs] Error 2
make[1]: *** [/home/johannes/src/linux/Makefile:1989: .] Error 2
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/5] btrfs: remove the PAGE_SIZE usage inside inline extent reads
2025-02-20 9:22 ` [PATCH 2/5] btrfs: remove the PAGE_SIZE usage inside inline extent reads Qu Wenruo
@ 2025-02-21 11:37 ` Johannes Thumshirn
0 siblings, 0 replies; 17+ messages in thread
From: Johannes Thumshirn @ 2025-02-21 11:37 UTC (permalink / raw)
To: WenRuo Qu, linux-btrfs@vger.kernel.org
On 20.02.25 10:25, Qu Wenruo wrote:
> The inline extent ram size should never exceed btrfs block size, there
> is no need to clamp the size against PAGE_SIZE.
>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> fs/btrfs/inode.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 3af74f3c5d75..d9ca92d1b927 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -6784,7 +6784,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
>
> read_extent_buffer(leaf, tmp, ptr, inline_size);
>
> - max_size = min_t(unsigned long, PAGE_SIZE, max_size);
> + max_size = min_t(unsigned long, sectorsize, max_size);
> ret = btrfs_decompress(compress_type, tmp, folio, 0, inline_size,
> max_size);
>
> @@ -6820,7 +6820,7 @@ static int read_inline_extent(struct btrfs_fs_info *fs_info,
> if (btrfs_file_extent_compression(path->nodes[0], fi) != BTRFS_COMPRESS_NONE)
> return uncompress_inline(path, folio, fi);
>
> - copy_size = min_t(u64, PAGE_SIZE,
> + copy_size = min_t(u64, sectorsize,
> btrfs_file_extent_ram_bytes(path->nodes[0], fi));
> kaddr = kmap_local_folio(folio, 0);
> read_extent_buffer(path->nodes[0], kaddr,
That'll make it compile:
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f94b80d4433d..f64869fad466 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6788,6 +6788,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
{
int ret;
struct extent_buffer *leaf = path->nodes[0];
+ u32 sectorsize = leaf->fs_info->sectorsize;
char *tmp;
size_t max_size;
unsigned long inline_size;
@@ -6825,6 +6826,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
static int read_inline_extent(struct btrfs_path *path, struct folio *folio)
{
struct btrfs_file_extent_item *fi;
+ u32 sectorsize;
void *kaddr;
size_t copy_size;
@@ -6832,6 +6834,7 @@ static int read_inline_extent(struct btrfs_path *path, struct folio *folio)
return 0;
ASSERT(folio_pos(folio) == 0);
+ sectorsize = folio_to_fs_info(folio)->sectorsize;
fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_file_extent_item);
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/5] btrfs: prepare subpage.c for larger folios support
2025-02-20 9:22 ` [PATCH 1/5] btrfs: prepare subpage.c " Qu Wenruo
@ 2025-02-21 12:06 ` Johannes Thumshirn
2025-02-22 5:03 ` Qu Wenruo
0 siblings, 1 reply; 17+ messages in thread
From: Johannes Thumshirn @ 2025-02-21 12:06 UTC (permalink / raw)
To: WenRuo Qu, linux-btrfs@vger.kernel.org
On 20.02.25 10:24, Qu Wenruo wrote:
> For the future of larger folio support, even if block size == page size,
> we may still hit a larger folio and need to attach a subpage structure to
> that larger folio.
>
> In that case we can no longer assume we need to go subpage routine only
> when block size < page size, but take folio size into the consideration.
>
> Prepare for such future by:
>
> - Use folio_size() instead of PAGE_SIZE
> - Make btrfs_alloc_subpage() to handle different folio sizes
> - Make btrfs_is_subpage() to do the check based on the folio
I personally would split this patch in 3 doing the above. Or at least
split out the brtfs_is_subpage() part in another patch.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] btrfs: prepare btrfs_launcher_folio() for larger folios support
2025-02-20 9:22 ` [PATCH 3/5] btrfs: prepare btrfs_launcher_folio() for larger folios support Qu Wenruo
@ 2025-02-21 12:08 ` Johannes Thumshirn
0 siblings, 0 replies; 17+ messages in thread
From: Johannes Thumshirn @ 2025-02-21 12:08 UTC (permalink / raw)
To: WenRuo Qu, linux-btrfs@vger.kernel.org
On 20.02.25 10:26, Qu Wenruo wrote:
> That function is only calling btrfs_qgroup_free_data(), which doesn't
> care the size of the folio.
about~^
> Just replace the fixed PAGE_SIZE with folio_size().
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support
2025-02-20 9:22 ` [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support Qu Wenruo
@ 2025-02-21 12:12 ` Johannes Thumshirn
2025-02-22 5:02 ` Qu Wenruo
2025-02-25 18:41 ` Nathan Chancellor
1 sibling, 1 reply; 17+ messages in thread
From: Johannes Thumshirn @ 2025-02-21 12:12 UTC (permalink / raw)
To: WenRuo Qu, linux-btrfs@vger.kernel.org
On 20.02.25 10:24, Qu Wenruo wrote:
> @@ -2468,8 +2468,8 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
> ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(end + 1, sectorsize));
>
> while (cur <= end) {
> - u64 cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
> - u32 cur_len = cur_end + 1 - cur;
> + u64 cur_end;
> + u32 cur_len;
> struct folio *folio;
>
> folio = filemap_get_folio(mapping, cur >> PAGE_SHIFT);
> @@ -2479,13 +2479,18 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
> * code is just in case, but shouldn't actually be run.
> */
> if (IS_ERR(folio)) {
> + cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
> + cur_len = cur_end + 1 - cur;
Why is it still using PAGE_SIZE here?
> btrfs_mark_ordered_io_finished(BTRFS_I(inode), NULL,
> cur, cur_len, false);
> mapping_set_error(mapping, PTR_ERR(folio));
> - cur = cur_end + 1;
> + cur = cur_end;
> continue;
> }
>
> + cur_end = min(folio_pos(folio) + folio_size(folio) - 1, end);
> + cur_len = cur_end + 1 - cur;
> +
> ASSERT(folio_test_locked(folio));
> if (pages_dirty && folio != locked_folio)
> ASSERT(folio_test_dirty(folio));
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] btrfs: prepare btrfs_page_mkwrite() for larger folios
2025-02-20 9:22 ` [PATCH 5/5] btrfs: prepare btrfs_page_mkwrite() for larger folios Qu Wenruo
@ 2025-02-21 12:22 ` Johannes Thumshirn
0 siblings, 0 replies; 17+ messages in thread
From: Johannes Thumshirn @ 2025-02-21 12:22 UTC (permalink / raw)
To: WenRuo Qu, linux-btrfs@vger.kernel.org
Looks good to me,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/5] btrfs: prepare for larger folios support
2025-02-21 11:23 ` [PATCH 0/5] btrfs: prepare for larger folios support Johannes Thumshirn
@ 2025-02-21 12:34 ` Filipe Manana
2025-02-21 22:33 ` Qu Wenruo
1 sibling, 0 replies; 17+ messages in thread
From: Filipe Manana @ 2025-02-21 12:34 UTC (permalink / raw)
To: Johannes Thumshirn; +Cc: WenRuo Qu, linux-btrfs@vger.kernel.org
On Fri, Feb 21, 2025 at 11:23 AM Johannes Thumshirn
<Johannes.Thumshirn@wdc.com> wrote:
>
> On 20.02.25 10:26, Qu Wenruo wrote:
> > Qu Wenruo (5):
> > btrfs: prepare subpage.c for larger folios support
> > btrfs: remove the PAGE_SIZE usage inside inline extent reads
> > btrfs: prepare btrfs_launcher_folio() for larger folios support
> > btrfs: prepare extent_io.c for future larger folio support
> > btrfs: prepare btrfs_page_mkwrite() for larger folios
> >
> > fs/btrfs/extent_io.c | 50 +++++++++++++++++++++++++-------------------
> > fs/btrfs/file.c | 19 +++++++++--------
> > fs/btrfs/inode.c | 8 +++----
> > fs/btrfs/subpage.c | 36 +++++++++++++++----------------
> > fs/btrfs/subpage.h | 24 ++++++++-------------
> > 5 files changed, 69 insertions(+), 68 deletions(-)
> >
>
> Hi Qu,
> What am I doing wrong?
>
> Applying: btrfs: prepare subpage.c for larger folios support
> Applying: btrfs: remove the PAGE_SIZE usage inside inline extent reads
> In file included from ./include/linux/kernel.h:28,
> from ./include/linux/cpumask.h:11,
> from ./include/linux/smp.h:13,
> from ./include/linux/lockdep.h:14,
> from ./include/linux/spinlock.h:63,
> from ./include/linux/swait.h:7,
> from ./include/linux/completion.h:12,
> from ./include/linux/crypto.h:15,
> from ./include/crypto/hash.h:12,
> from fs/btrfs/inode.c:6:
> fs/btrfs/inode.c: In function ‘uncompress_inline’:
> fs/btrfs/inode.c:6807:41: error: ‘sectorsize’ undeclared (first use in
> this function); did you mean ‘sector_t’?
So this seems to depend on this patchset which introduces that variable:
https://lore.kernel.org/linux-btrfs/cover.1739608189.git.wqu@suse.com/
But that patset depends on other unmerged patches, so not easy to
follow and review.
I was just trying to review that patchset.
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~~~~~~
> ./include/linux/minmax.h:86:23: note: in definition of macro
> ‘__cmp_once_unique’
> 86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
> | ^
> ./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
> 161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
> | ^~~~~~~~~~
> fs/btrfs/inode.c:6807:20: note: in expansion of macro ‘min_t’
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~
> fs/btrfs/inode.c:6807:41: note: each undeclared identifier is reported
> only once for each function it appears in
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~~~~~~
> ./include/linux/minmax.h:86:23: note: in definition of macro
> ‘__cmp_once_unique’
> 86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
> | ^
> ./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
> 161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
> | ^~~~~~~~~~
> fs/btrfs/inode.c:6807:20: note: in expansion of macro ‘min_t’
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~
> fs/btrfs/inode.c: In function ‘read_inline_extent’:
> fs/btrfs/inode.c:6841:32: error: ‘sectorsize’ undeclared (first use in
> this function); did you mean ‘sector_t’?
> 6841 | copy_size = min_t(u64, sectorsize,
> | ^~~~~~~~~~
> ./include/linux/minmax.h:86:23: note: in definition of macro
> ‘__cmp_once_unique’
> 86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
> | ^
> ./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
> 161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
> | ^~~~~~~~~~
> fs/btrfs/inode.c:6841:21: note: in expansion of macro ‘min_t’
> 6841 | copy_size = min_t(u64, sectorsize,
> | ^~~~~
> make[4]: *** [scripts/Makefile.build:207: fs/btrfs/inode.o] Error 1
> make[3]: *** [scripts/Makefile.build:465: fs/btrfs] Error 2
> make[2]: *** [scripts/Makefile.build:465: fs] Error 2
> make[1]: *** [/home/johannes/src/linux/Makefile:1989: .] Error 2
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/5] btrfs: prepare for larger folios support
2025-02-21 11:23 ` [PATCH 0/5] btrfs: prepare for larger folios support Johannes Thumshirn
2025-02-21 12:34 ` Filipe Manana
@ 2025-02-21 22:33 ` Qu Wenruo
1 sibling, 0 replies; 17+ messages in thread
From: Qu Wenruo @ 2025-02-21 22:33 UTC (permalink / raw)
To: Johannes Thumshirn, WenRuo Qu, linux-btrfs@vger.kernel.org
在 2025/2/21 21:53, Johannes Thumshirn 写道:
> On 20.02.25 10:26, Qu Wenruo wrote:
>> Qu Wenruo (5):
>> btrfs: prepare subpage.c for larger folios support
>> btrfs: remove the PAGE_SIZE usage inside inline extent reads
>> btrfs: prepare btrfs_launcher_folio() for larger folios support
>> btrfs: prepare extent_io.c for future larger folio support
>> btrfs: prepare btrfs_page_mkwrite() for larger folios
>>
>> fs/btrfs/extent_io.c | 50 +++++++++++++++++++++++++-------------------
>> fs/btrfs/file.c | 19 +++++++++--------
>> fs/btrfs/inode.c | 8 +++----
>> fs/btrfs/subpage.c | 36 +++++++++++++++----------------
>> fs/btrfs/subpage.h | 24 ++++++++-------------
>> 5 files changed, 69 insertions(+), 68 deletions(-)
>>
>
> Hi Qu,
> What am I doing wrong?
>
> Applying: btrfs: prepare subpage.c for larger folios support
> Applying: btrfs: remove the PAGE_SIZE usage inside inline extent reads
I believe it's missing some dependency.
In fact it looks like it's missing the following patch:
https://lore.kernel.org/linux-btrfs/4e0368b2d4ab74e1a2cef76000ea75cb3198696a.1739608189.git.wqu@suse.com/
I'm sorry but there are too many pending subpage patches, thus it's
harder and harder to properly trace them...
Thanks,
Qu
> In file included from ./include/linux/kernel.h:28,
> from ./include/linux/cpumask.h:11,
> from ./include/linux/smp.h:13,
> from ./include/linux/lockdep.h:14,
> from ./include/linux/spinlock.h:63,
> from ./include/linux/swait.h:7,
> from ./include/linux/completion.h:12,
> from ./include/linux/crypto.h:15,
> from ./include/crypto/hash.h:12,
> from fs/btrfs/inode.c:6:
> fs/btrfs/inode.c: In function ‘uncompress_inline’:
> fs/btrfs/inode.c:6807:41: error: ‘sectorsize’ undeclared (first use in
> this function); did you mean ‘sector_t’?
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~~~~~~
> ./include/linux/minmax.h:86:23: note: in definition of macro
> ‘__cmp_once_unique’
> 86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
> | ^
> ./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
> 161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
> | ^~~~~~~~~~
> fs/btrfs/inode.c:6807:20: note: in expansion of macro ‘min_t’
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~
> fs/btrfs/inode.c:6807:41: note: each undeclared identifier is reported
> only once for each function it appears in
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~~~~~~
> ./include/linux/minmax.h:86:23: note: in definition of macro
> ‘__cmp_once_unique’
> 86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
> | ^
> ./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
> 161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
> | ^~~~~~~~~~
> fs/btrfs/inode.c:6807:20: note: in expansion of macro ‘min_t’
> 6807 | max_size = min_t(unsigned long, sectorsize, max_size);
> | ^~~~~
> fs/btrfs/inode.c: In function ‘read_inline_extent’:
> fs/btrfs/inode.c:6841:32: error: ‘sectorsize’ undeclared (first use in
> this function); did you mean ‘sector_t’?
> 6841 | copy_size = min_t(u64, sectorsize,
> | ^~~~~~~~~~
> ./include/linux/minmax.h:86:23: note: in definition of macro
> ‘__cmp_once_unique’
> 86 | ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); })
> | ^
> ./include/linux/minmax.h:161:27: note: in expansion of macro ‘__cmp_once’
> 161 | #define min_t(type, x, y) __cmp_once(min, type, x, y)
> | ^~~~~~~~~~
> fs/btrfs/inode.c:6841:21: note: in expansion of macro ‘min_t’
> 6841 | copy_size = min_t(u64, sectorsize,
> | ^~~~~
> make[4]: *** [scripts/Makefile.build:207: fs/btrfs/inode.o] Error 1
> make[3]: *** [scripts/Makefile.build:465: fs/btrfs] Error 2
> make[2]: *** [scripts/Makefile.build:465: fs] Error 2
> make[1]: *** [/home/johannes/src/linux/Makefile:1989: .] Error 2
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support
2025-02-21 12:12 ` Johannes Thumshirn
@ 2025-02-22 5:02 ` Qu Wenruo
0 siblings, 0 replies; 17+ messages in thread
From: Qu Wenruo @ 2025-02-22 5:02 UTC (permalink / raw)
To: Johannes Thumshirn, WenRuo Qu, linux-btrfs@vger.kernel.org
在 2025/2/21 22:42, Johannes Thumshirn 写道:
> On 20.02.25 10:24, Qu Wenruo wrote:
>> @@ -2468,8 +2468,8 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
>> ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(end + 1, sectorsize));
>>
>> while (cur <= end) {
>> - u64 cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
>> - u32 cur_len = cur_end + 1 - cur;
>> + u64 cur_end;
>> + u32 cur_len;
>> struct folio *folio;
>>
>> folio = filemap_get_folio(mapping, cur >> PAGE_SHIFT);
>> @@ -2479,13 +2479,18 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
>> * code is just in case, but shouldn't actually be run.
>> */
>> if (IS_ERR(folio)) {
>> + cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
>> + cur_len = cur_end + 1 - cur;
>
> Why is it still using PAGE_SIZE here?
This is because we are at a failure path where there is no folio.
But we still want to skip to the next slot (may or may not exist
though), so we have to increase the bytenr by the minimal unit of
filemap, which is still a page.
Thanks,
Qu
>
>> btrfs_mark_ordered_io_finished(BTRFS_I(inode), NULL,
>> cur, cur_len, false);
>> mapping_set_error(mapping, PTR_ERR(folio));
>> - cur = cur_end + 1;
>> + cur = cur_end;
>> continue;
>> }
>>
>> + cur_end = min(folio_pos(folio) + folio_size(folio) - 1, end);
>> + cur_len = cur_end + 1 - cur;
>> +
>> ASSERT(folio_test_locked(folio));
>> if (pages_dirty && folio != locked_folio)
>> ASSERT(folio_test_dirty(folio));
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/5] btrfs: prepare subpage.c for larger folios support
2025-02-21 12:06 ` Johannes Thumshirn
@ 2025-02-22 5:03 ` Qu Wenruo
0 siblings, 0 replies; 17+ messages in thread
From: Qu Wenruo @ 2025-02-22 5:03 UTC (permalink / raw)
To: Johannes Thumshirn, WenRuo Qu, linux-btrfs@vger.kernel.org
在 2025/2/21 22:36, Johannes Thumshirn 写道:
> On 20.02.25 10:24, Qu Wenruo wrote:
>> For the future of larger folio support, even if block size == page size,
>> we may still hit a larger folio and need to attach a subpage structure to
>> that larger folio.
>>
>> In that case we can no longer assume we need to go subpage routine only
>> when block size < page size, but take folio size into the consideration.
>>
>> Prepare for such future by:
>>
>> - Use folio_size() instead of PAGE_SIZE
>> - Make btrfs_alloc_subpage() to handle different folio sizes
>> - Make btrfs_is_subpage() to do the check based on the folio
>
> I personally would split this patch in 3 doing the above. Or at least
> split out the brtfs_is_subpage() part in another patch.
>
Sure, and the next update will only be sent after all the dependency got
merged into for-next branch.
Thanks,
Qu
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support
2025-02-20 9:22 ` [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support Qu Wenruo
2025-02-21 12:12 ` Johannes Thumshirn
@ 2025-02-25 18:41 ` Nathan Chancellor
1 sibling, 0 replies; 17+ messages in thread
From: Nathan Chancellor @ 2025-02-25 18:41 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs
On Thu, Feb 20, 2025 at 07:52:25PM +1030, Qu Wenruo wrote:
> When we're handling folios from filemap, we can no longer assume all
> folios are page sized.
>
> Thus for call sites assuming the folio is page sized, change the
> PAGE_SIZE usage to folio_size() instead.
>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> fs/btrfs/extent_io.c | 33 +++++++++++++++++++--------------
> 1 file changed, 19 insertions(+), 14 deletions(-)
>
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index e1efb6419601..88bac9a32919 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -425,7 +425,7 @@ static void end_folio_read(struct folio *folio, bool uptodate, u64 start, u32 le
> struct btrfs_fs_info *fs_info = folio_to_fs_info(folio);
>
> ASSERT(folio_pos(folio) <= start &&
> - start + len <= folio_pos(folio) + PAGE_SIZE);
> + start + len <= folio_pos(folio) + folio_size(folio));
>
> if (uptodate && btrfs_verify_folio(folio, start, len))
> btrfs_folio_set_uptodate(fs_info, folio, start, len);
> @@ -492,7 +492,7 @@ static void begin_folio_read(struct btrfs_fs_info *fs_info, struct folio *folio)
> return;
>
> ASSERT(folio_test_private(folio));
> - btrfs_folio_set_lock(fs_info, folio, folio_pos(folio), PAGE_SIZE);
> + btrfs_folio_set_lock(fs_info, folio, folio_pos(folio), folio_size(folio));
> }
>
> /*
> @@ -753,7 +753,7 @@ static void submit_extent_folio(struct btrfs_bio_ctrl *bio_ctrl,
> {
> struct btrfs_inode *inode = folio_to_inode(folio);
>
> - ASSERT(pg_offset + size <= PAGE_SIZE);
> + ASSERT(pg_offset + size <= folio_size(folio));
> ASSERT(bio_ctrl->end_io_func);
>
> if (bio_ctrl->bbio &&
> @@ -935,7 +935,7 @@ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
> struct inode *inode = folio->mapping->host;
> struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
> u64 start = folio_pos(folio);
> - const u64 end = start + PAGE_SIZE - 1;
> + const u64 end = start + folio_size(folio) - 1;
> u64 cur = start;
> u64 extent_offset;
> u64 last_byte = i_size_read(inode);
> @@ -1277,7 +1277,7 @@ static void set_delalloc_bitmap(struct folio *folio, unsigned long *delalloc_bit
> unsigned int start_bit;
> unsigned int nbits;
>
> - ASSERT(start >= folio_start && start + len <= folio_start + PAGE_SIZE);
> + ASSERT(start >= folio_start && start + len <= folio_start + folio_size(folio));
> start_bit = (start - folio_start) >> fs_info->sectorsize_bits;
> nbits = len >> fs_info->sectorsize_bits;
> ASSERT(bitmap_test_range_all_zero(delalloc_bitmap, start_bit, nbits));
> @@ -1295,7 +1295,7 @@ static bool find_next_delalloc_bitmap(struct folio *folio,
> unsigned int first_zero;
> unsigned int first_set;
>
> - ASSERT(start >= folio_start && start < folio_start + PAGE_SIZE);
> + ASSERT(start >= folio_start && start < folio_start + folio_size(folio));
>
> start_bit = (start - folio_start) >> fs_info->sectorsize_bits;
> first_set = find_next_bit(delalloc_bitmap, bitmap_size, start_bit);
> @@ -1497,10 +1497,10 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
> delalloc_end = page_end;
> /*
> * delalloc_end is already one less than the total length, so
> - * we don't subtract one from PAGE_SIZE
> + * we don't subtract one from folio_size().
> */
> delalloc_to_write +=
> - DIV_ROUND_UP(delalloc_end + 1 - page_start, PAGE_SIZE);
> + DIV_ROUND_UP(delalloc_end + 1 - page_start, folio_size(folio));
>
> /*
> * If all ranges are submitted asynchronously, we just need to account
> @@ -1737,7 +1737,7 @@ static int extent_writepage(struct folio *folio, struct btrfs_bio_ctrl *bio_ctrl
> goto done;
>
> ret = extent_writepage_io(inode, folio, folio_pos(folio),
> - PAGE_SIZE, bio_ctrl, i_size);
> + folio_size(folio), bio_ctrl, i_size);
> if (ret == 1)
> return 0;
> if (ret < 0)
> @@ -2468,8 +2468,8 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
> ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(end + 1, sectorsize));
>
> while (cur <= end) {
> - u64 cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
> - u32 cur_len = cur_end + 1 - cur;
> + u64 cur_end;
> + u32 cur_len;
> struct folio *folio;
>
> folio = filemap_get_folio(mapping, cur >> PAGE_SHIFT);
> @@ -2479,13 +2479,18 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
> * code is just in case, but shouldn't actually be run.
> */
> if (IS_ERR(folio)) {
> + cur_end = min(round_down(cur, PAGE_SIZE) + PAGE_SIZE - 1, end);
> + cur_len = cur_end + 1 - cur;
> btrfs_mark_ordered_io_finished(BTRFS_I(inode), NULL,
> cur, cur_len, false);
> mapping_set_error(mapping, PTR_ERR(folio));
> - cur = cur_end + 1;
> + cur = cur_end;
> continue;
> }
>
> + cur_end = min(folio_pos(folio) + folio_size(folio) - 1, end);
As the kernel test robot points out, this breaks the build for 32-bit
targets in -next because folio_pos() returns loff_t and folio_size()
returns size_t, which is 'unsigned int' for 32-bit instead of 'unsigned
long', so the whole expression gets promoted to 'long long' from the
loff_t, mismatching the sign of end. I just silenced it with a cast to
u64 before folio_pos() but that is likely incorrect as a formal fix,
hence just the extra comment.
> + cur_len = cur_end + 1 - cur;
> +
> ASSERT(folio_test_locked(folio));
> if (pages_dirty && folio != locked_folio)
> ASSERT(folio_test_dirty(folio));
> @@ -2597,7 +2602,7 @@ static bool try_release_extent_state(struct extent_io_tree *tree,
> struct folio *folio)
> {
> u64 start = folio_pos(folio);
> - u64 end = start + PAGE_SIZE - 1;
> + u64 end = start + folio_size(folio) - 1;
> bool ret;
>
> if (test_range_bit_exists(tree, start, end, EXTENT_LOCKED)) {
> @@ -2635,7 +2640,7 @@ static bool try_release_extent_state(struct extent_io_tree *tree,
> bool try_release_extent_mapping(struct folio *folio, gfp_t mask)
> {
> u64 start = folio_pos(folio);
> - u64 end = start + PAGE_SIZE - 1;
> + u64 end = start + folio_size(folio) - 1;
> struct btrfs_inode *inode = folio_to_inode(folio);
> struct extent_io_tree *io_tree = &inode->io_tree;
>
> --
> 2.48.1
>
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-02-25 18:41 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-20 9:22 [PATCH 0/5] btrfs: prepare for larger folios support Qu Wenruo
2025-02-20 9:22 ` [PATCH 1/5] btrfs: prepare subpage.c " Qu Wenruo
2025-02-21 12:06 ` Johannes Thumshirn
2025-02-22 5:03 ` Qu Wenruo
2025-02-20 9:22 ` [PATCH 2/5] btrfs: remove the PAGE_SIZE usage inside inline extent reads Qu Wenruo
2025-02-21 11:37 ` Johannes Thumshirn
2025-02-20 9:22 ` [PATCH 3/5] btrfs: prepare btrfs_launcher_folio() for larger folios support Qu Wenruo
2025-02-21 12:08 ` Johannes Thumshirn
2025-02-20 9:22 ` [PATCH 4/5] btrfs: prepare extent_io.c for future larger folio support Qu Wenruo
2025-02-21 12:12 ` Johannes Thumshirn
2025-02-22 5:02 ` Qu Wenruo
2025-02-25 18:41 ` Nathan Chancellor
2025-02-20 9:22 ` [PATCH 5/5] btrfs: prepare btrfs_page_mkwrite() for larger folios Qu Wenruo
2025-02-21 12:22 ` Johannes Thumshirn
2025-02-21 11:23 ` [PATCH 0/5] btrfs: prepare for larger folios support Johannes Thumshirn
2025-02-21 12:34 ` Filipe Manana
2025-02-21 22:33 ` Qu Wenruo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox