* [PATCH 1/3] btrfs: use kvmalloc() for btrfs_encoded_read_inline()
2026-09-23 5:44 [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page Qu Wenruo
@ 2026-09-23 5:44 ` Qu Wenruo
2026-09-23 5:44 ` [PATCH 2/3] btrfs: use kvzalloc() for btrfs_raid_bio::csum_buf Qu Wenruo
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-09-23 5:44 UTC (permalink / raw)
To: linux-btrfs
Near the end of that function, we copy the inline extent data into a
buffer, then copy the buffer back to the iter.
However it is possible to have an inlined extent larger than a page.
For example, a btrfs filesystem is created on a 64K page sized system
with 64K sectorsize, mounted with max_inline=32K, and a 32K inline extent
is created.
Then the fs is mounted on x86_64 (4K page size) with the experimental
larger block size support.
In that case, kmalloc() is called to allocate a 32K buffer, which can
fail on systems with fragmented available memory.
Meanwhile there is no need to allocate physically contiguous memory,
so change it to kvmalloc() to reduce the chance of memory allocation
failure.
Assisted-by: LLM (finding callsites doing multi-page kmalloc)
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 53f4532593b3..d04a7dce93ff 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9571,7 +9571,7 @@ static ssize_t btrfs_encoded_read_inline(
ptr += iocb->ki_pos - extent_start;
}
- tmp = kmalloc(count, GFP_NOFS);
+ tmp = kvmalloc(count, GFP_NOFS);
if (!tmp)
return -ENOMEM;
@@ -9584,7 +9584,7 @@ static ssize_t btrfs_encoded_read_inline(
ret = copy_to_iter(tmp, count, iter);
if (ret != count)
ret = -EFAULT;
- kfree(tmp);
+ kvfree(tmp);
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/3] btrfs: use kvzalloc() for btrfs_raid_bio::csum_buf
2026-09-23 5:44 [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page Qu Wenruo
2026-09-23 5:44 ` [PATCH 1/3] btrfs: use kvmalloc() for btrfs_encoded_read_inline() Qu Wenruo
@ 2026-09-23 5:44 ` Qu Wenruo
2026-09-23 5:44 ` [PATCH 3/3] btrfs: use kvmalloc() inside test_eb_bitmaps() Qu Wenruo
2026-09-23 7:42 ` [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page Sun YangKai
3 siblings, 0 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-09-23 5:44 UTC (permalink / raw)
To: linux-btrfs
That member is to store the checksum for the full stripe, and for the
following setup we can have a buffer size larger than 4K:
sectorsize 4K, csum type SHA256 (32 bytes per sector) and 10 data
stripes.
The csum_buf size would be:
stripe_nsectors * nr_data * csum_size
16 * 10 * 32 = 5120
This means kzalloc() will require 2 physical contiguous pages, which may
not always be available if the available memory is highly fragmented.
However such allocation failure should be very rare, as small order
(order <= 3) allocation is not that easy to fail.
To reach costly order (>= 4) it requires 128 data stripes, which is beyond
sanity.
Change the allocation to use kvzalloc() instead, so that if we need
multiple pages as buffer, we still have a fallback that allocates single
pages and maps them into a virtually contiguous buffer.
For most cases where the buffer is smaller than a page, the kvzalloc()
should fallback to kzalloc(), with minimal overhead.
Assisted-by: LLM (finding callsites doing multi-page kmalloc)
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/raid56.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 8ec24dbb180f..6e7ab0bb025a 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -946,7 +946,7 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t status)
struct bio *cur = bio_list_get(&rbio->bio_list);
struct bio *extra;
- kfree(rbio->csum_buf);
+ kvfree(rbio->csum_buf);
bitmap_free(rbio->csum_bitmap);
rbio->csum_buf = NULL;
rbio->csum_bitmap = NULL;
@@ -2304,8 +2304,8 @@ static void fill_data_csums(struct btrfs_raid_bio *rbio)
rbio->bioc->map_type & BTRFS_BLOCK_GROUP_METADATA)
return;
- rbio->csum_buf = kzalloc(rbio->nr_data * rbio->stripe_nsectors *
- fs_info->csum_size, GFP_NOFS);
+ rbio->csum_buf = kvzalloc(rbio->nr_data * rbio->stripe_nsectors *
+ fs_info->csum_size, GFP_NOFS);
rbio->csum_bitmap = bitmap_zalloc(rbio->nr_data * rbio->stripe_nsectors,
GFP_NOFS);
if (!rbio->csum_buf || !rbio->csum_bitmap) {
@@ -2340,7 +2340,7 @@ static void fill_data_csums(struct btrfs_raid_bio *rbio)
"sub-stripe write for full stripe %llu is not safe, failed to get csum: %d",
rbio->bioc->full_stripe_logical, ret);
no_csum:
- kfree(rbio->csum_buf);
+ kvfree(rbio->csum_buf);
bitmap_free(rbio->csum_bitmap);
rbio->csum_buf = NULL;
rbio->csum_bitmap = NULL;
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 3/3] btrfs: use kvmalloc() inside test_eb_bitmaps()
2026-09-23 5:44 [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page Qu Wenruo
2026-09-23 5:44 ` [PATCH 1/3] btrfs: use kvmalloc() for btrfs_encoded_read_inline() Qu Wenruo
2026-09-23 5:44 ` [PATCH 2/3] btrfs: use kvzalloc() for btrfs_raid_bio::csum_buf Qu Wenruo
@ 2026-09-23 5:44 ` Qu Wenruo
2026-09-23 7:42 ` [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page Sun YangKai
3 siblings, 0 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-09-23 5:44 UTC (permalink / raw)
To: linux-btrfs
The reference bitmap has the same size as nodesize, and the selftests
use nodesize as large as 64K, so the kmalloc() may fail if the available
memory is fragmented.
However this should be very rare. Firstly this requires
CONFIG_BTRFS_FS_RUN_SANITY_TESTS, which is only enabled for developers.
Secondly for most users the btrfs module is loaded at boot time, thus
there should be more than enough available space to fulfill that
kmalloc() call.
Secondly for most users the btrfs module is loaded at boot time, so there
should be more than enough available memory.
Use kvmalloc() to reduce the chance of allocation failure.
Assisted-by: LLM (finding callsites doing multi-page kmalloc)
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/tests/extent-io-tests.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
index cd045778400d..0a8d65df0eba 100644
--- a/fs/btrfs/tests/extent-io-tests.c
+++ b/fs/btrfs/tests/extent-io-tests.c
@@ -507,7 +507,7 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb)
static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
{
struct btrfs_fs_info *fs_info;
- unsigned long AUTO_KFREE(bitmap);
+ unsigned long AUTO_KVFREE(bitmap);
struct extent_buffer *eb = NULL;
int ret;
@@ -519,7 +519,7 @@ static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
return -ENOMEM;
}
- bitmap = kmalloc(nodesize, GFP_KERNEL);
+ bitmap = kvmalloc(nodesize, GFP_KERNEL);
if (!bitmap) {
test_err("couldn't allocate test bitmap");
ret = -ENOMEM;
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page
2026-09-23 5:44 [PATCH 0/3] btrfs: use kvmalloc() for cases where allocation can be more than one page Qu Wenruo
` (2 preceding siblings ...)
2026-09-23 5:44 ` [PATCH 3/3] btrfs: use kvmalloc() inside test_eb_bitmaps() Qu Wenruo
@ 2026-09-23 7:42 ` Sun YangKai
3 siblings, 0 replies; 5+ messages in thread
From: Sun YangKai @ 2026-09-23 7:42 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs
On 2026/9/23 13:44, Qu Wenruo wrote:
> There are still some cases where kmalloc() and its variants are called
> where the memory allocated can be multiple pages on x86_64.
>
> Normally any kmalloc() with a size that <= PAGE_ALLOC_COSTLY_ORDER (3)
> should not fail that easily, so even we allocate a multi-page buffer
> using kmalloc() as long as it's not reaching 64K (4K page size) it
> should still be fine.
>
> Thus those cases are all very rare:
>
> - An inlined extent larger than 4K
> This can only be archived by a system with page size larger than 4K,
> along with larger max_inline.
>
> And still, only 64K sized inlined extent can really cause problems.
>
> - Too many RAID56 data stripes with SHA256
> To go beyond 4K, it only requires 9 data stripes, but to reach 64K
> (order > 3) it requires 128 data stripes which is beyond sanity.
>
> - Fragmented memory at btrfs module load time
> This is in fact more common than the above 2 cases, but this requires
> CONFIG_BTRFS_FS_RUN_SANITY_TESTS and load the module after the memory
> is fragmented, it's still very rare.
>
> So all of those fixes are just another bike shred problem, but
> considering it's not that hard to fix, so here comes the patches.
>
> Qu Wenruo (3):
> btrfs: use kvmalloc() for btrfs_encoded_read_inline()
> btrfs: use kvzalloc() for btrfs_raid_bio::csum_buf
> btrfs: use kvmalloc() inside test_eb_bitmaps()
>
> fs/btrfs/inode.c | 4 ++--
> fs/btrfs/raid56.c | 8 ++++----
> fs/btrfs/tests/extent-io-tests.c | 4 ++--
> 3 files changed, 8 insertions(+), 8 deletions(-)
>
Looks good to me
Reviewed-by: Sun YangKai <sunyangkai@fygo.io>
^ permalink raw reply [flat|nested] 5+ messages in thread