[PATCH RFC 4/8] mm, slab: make SLUB_TINY handling dynamic for sizing decisions

From: Vlastimil Babka (SUSE)

Date: Wed Sep 23 2026 - 12:02:38 EST


Enabling CONFIG_SLUB_TINY results in the caches' min partial slabs
threshold to be zero, thus every slab where all objects become free is
freed immediately. It also sets the default slab_max_order to 1, with
the goal of reducing the potential of internal slab fragmentation.

Rework both of these decisions to be based on the newly introduced
slab_tiny_enabled flag instead of #ifdefs. It's still possible to
override the reduced slab_max_order with the boot parameter, as before.

Signed-off-by: Vlastimil Babka (SUSE) <vbabka@xxxxxxxxxx>
---
mm/slub.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/mm/slub.c b/mm/slub.c
index 2a7b3b3b91b5..2c8477033700 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -272,7 +272,6 @@ void *fixup_red_left(struct kmem_cache *s, void *p)
/* Enable to log cmpxchg failures */
#undef SLUB_DEBUG_CMPXCHG

-#ifndef CONFIG_SLUB_TINY
/*
* Minimum number of partial slabs. These will be left on the partial
* lists even if they are empty. kmem_cache_shrink may reclaim them.
@@ -285,10 +284,6 @@ void *fixup_red_left(struct kmem_cache *s, void *p)
* sort the partial list by the number of objects in use.
*/
#define MAX_PARTIAL 10
-#else
-#define MIN_PARTIAL 0
-#define MAX_PARTIAL 0
-#endif

#define DEBUG_DEFAULT_FLAGS (SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | \
SLAB_POISON | SLAB_STORE_USER)
@@ -7604,8 +7599,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_bulk_noprof);
* take the list_lock.
*/
static unsigned int slab_min_order;
-static unsigned int slab_max_order =
- IS_ENABLED(CONFIG_SLUB_TINY) ? 1 : PAGE_ALLOC_COSTLY_ORDER;
+static unsigned int slab_max_order = PAGE_ALLOC_COSTLY_ORDER;
static unsigned int slab_min_objects;

/*
@@ -7924,7 +7918,7 @@ static unsigned int calculate_sheaf_capacity(struct kmem_cache *s,
size_t size;


- if (IS_ENABLED(CONFIG_SLUB_TINY) || s->flags & SLAB_DEBUG_FLAGS)
+ if (slab_tiny_enabled || s->flags & SLAB_DEBUG_FLAGS)
return 0;

/*
@@ -8660,6 +8654,9 @@ void __init kmem_cache_init(void)

slab_obj_ext_has_codetag_init();

+ if (slab_tiny_enabled)
+ slab_max_order = 1;
+
if (slab_max_order_param <= MAX_PAGE_ORDER)
slab_max_order = slab_max_order_param;

@@ -8783,6 +8780,8 @@ int do_kmem_cache_create(struct kmem_cache *s, const char *name,
*/
s->min_partial = min_t(unsigned long, MAX_PARTIAL, ilog2(s->size) / 2);
s->min_partial = max_t(unsigned long, MIN_PARTIAL, s->min_partial);
+ if (slab_tiny_enabled)
+ s->min_partial = 0;

s->cpu_sheaves = alloc_percpu(struct slub_percpu_sheaves);
if (!s->cpu_sheaves) {

--
2.55.0