From: Filipe Manana Date: Wed, 15 Apr 2026 11:26:40 +0000 (+0100) Subject: btrfs: use a kmem_cache for block groups X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d293344c2249dc716d26d3d55a9261989da32c50;p=thirdparty%2Flinux.git btrfs: use a kmem_cache for block groups We are currently allocating block groups using the generic slabs, and given that the size of btrfs_block_group structure is 672 bytes (on a release kernel), we end up using the kmalloc-1024 slab and therefore waste quite some memory since on a 4K page system we can only fit 4 block groups per page. The block groups are also allocated and delallocated with some frequency, specially if we have auto reclaim enabled. So use a kmem_cache for block groups, this way on a 4K page system we can fit 6 block groups per page instead of 4. Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba --- diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index b611c64119dbc..a32de3a822d24 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -22,6 +22,23 @@ #include "accessors.h" #include "extent-tree.h" +static struct kmem_cache *block_group_cache; + +int __init btrfs_init_block_group(void) +{ + block_group_cache = kmem_cache_create("btrfs_block_group", + sizeof(struct btrfs_block_group), + 0, 0, NULL); + if (!block_group_cache) + return -ENOMEM; + return 0; +} + +void __cold btrfs_exit_block_group(void) +{ + kmem_cache_destroy(block_group_cache); +} + #ifdef CONFIG_BTRFS_DEBUG int btrfs_should_fragment_free_space(const struct btrfs_block_group *block_group) { @@ -182,7 +199,7 @@ void btrfs_put_block_group(struct btrfs_block_group *cache) kfree(cache->free_space_ctl); btrfs_free_chunk_map(cache->physical_map); - kfree(cache); + kmem_cache_free(block_group_cache, cache); } } @@ -2371,13 +2388,13 @@ static struct btrfs_block_group *btrfs_create_block_group( { struct btrfs_block_group *cache; - cache = kzalloc_obj(*cache, GFP_NOFS); + cache = kmem_cache_zalloc(block_group_cache, GFP_NOFS); if (!cache) return NULL; cache->free_space_ctl = kzalloc_obj(*cache->free_space_ctl, GFP_NOFS); if (!cache->free_space_ctl) { - kfree(cache); + kmem_cache_free(block_group_cache, cache); return NULL; } diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index 0504cb3579921..b414f4268d2d3 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -320,6 +320,9 @@ static inline u64 btrfs_block_group_available_space(const struct btrfs_block_gro int btrfs_should_fragment_free_space(const struct btrfs_block_group *block_group); #endif +int __init btrfs_init_block_group(void); +void __cold btrfs_exit_block_group(void); + struct btrfs_block_group *btrfs_lookup_first_block_group( struct btrfs_fs_info *info, u64 bytenr); struct btrfs_block_group *btrfs_lookup_block_group( diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f67a268f36a6d..a60bce413d33b 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2603,6 +2603,9 @@ static const struct init_sequence mod_init_seq[] = { }, { .init_func = btrfs_init_compress, .exit_func = btrfs_exit_compress, + }, { + .init_func = btrfs_init_block_group, + .exit_func = btrfs_exit_block_group, }, { .init_func = btrfs_init_cachep, .exit_func = btrfs_destroy_cachep,