[PATCH v2 3/6] mm/slab: Support disabling SLAB_BUCKETS at boot
From: Chris Down
Date: Thu Oct 29 2026 - 02:09:42 EST
SLAB_BUCKETS gives allocations with user-controlled size and contents,
like memdup_user() and msg_msg, their own set of kmalloc caches, at the
cost of the memory for those caches. It can only be chosen at build
time, so hosts which want it and hosts which would rather not pay for it
need separate kernels.
Add a slab_buckets= early parameter, enabled by default on kernels built
with CONFIG_SLAB_BUCKETS=y, so that it can be turned off at boot.
Signed-off-by: Chris Down <chris@xxxxxxxxxxxxxx>
---
.../admin-guide/kernel-parameters.txt | 8 ++++++
mm/Kconfig | 4 +++
mm/slab_common.c | 26 +++++++++++++++----
3 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4bdd2..de2fd6963a16 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7001,6 +7001,14 @@ Kernel parameters
apic=verbose is specified.
Example: apic=debug show_lapic=all
+ slab_buckets= [MM,EARLY]
+ Format: <bool>
+ Enable or disable separate kmalloc buckets on kernels
+ built with CONFIG_SLAB_BUCKETS=y. When disabled,
+ allocations use regular kmalloc caches. Ignored
+ without that option.
+ Default: on.
+
slab_debug[=options[,slabs][;[options[,slabs]]...]] [MM]
Enabling slab_debug allows one to determine the
culprit if slab objects become corrupted. Enabling
diff --git a/mm/Kconfig b/mm/Kconfig
index 92ff97ff24fb..48078c1fd26f 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -231,6 +231,10 @@ config SLAB_BUCKETS
of extra pages since the bulk of user-controlled allocations
are relatively long-lived.
+ The separate buckets can be disabled at boot with the
+ "slab_buckets=0" kernel parameter, in which case these
+ allocations use the regular kmalloc caches.
+
If unsure, say Y.
config SLUB_STATS
diff --git a/mm/slab_common.c b/mm/slab_common.c
index e66c0778ee98..b7a46c368ab1 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -410,6 +410,16 @@ EXPORT_SYMBOL(__kmem_cache_create_args);
static struct kmem_cache *kmem_buckets_cache __ro_after_init;
+static bool slab_buckets_enabled __ro_after_init = IS_ENABLED(CONFIG_SLAB_BUCKETS);
+
+#ifdef CONFIG_SLAB_BUCKETS
+static int __init setup_slab_buckets(char *str)
+{
+ return kstrtobool(str, &slab_buckets_enabled);
+}
+early_param("slab_buckets", setup_slab_buckets);
+#endif
+
/**
* kmem_buckets_create - Create a set of caches that handle dynamic sized
* allocations via kmem_buckets_alloc()
@@ -424,10 +434,12 @@ static struct kmem_cache *kmem_buckets_cache __ro_after_init;
*
* Context: Cannot be called within an interrupt, but can be interrupted.
*
- * Return: a pointer to the cache on success, NULL on failure. When
- * CONFIG_SLAB_BUCKETS is not enabled, ZERO_SIZE_PTR is returned, and
- * subsequent calls to kmem_buckets_alloc() will fall back to kmalloc().
- * (i.e. callers only need to check for NULL on failure.)
+ * Return: a pointer to the cache on success, NULL on failure or when the
+ * separate buckets were disabled with the "slab_buckets=0" boot parameter.
+ * When CONFIG_SLAB_BUCKETS is not enabled, ZERO_SIZE_PTR is returned. In all
+ * of these cases subsequent calls to kmem_buckets_alloc() with the returned
+ * value fall back to kmalloc(), so callers that can live without separate
+ * buckets do not need to check the return value.
*/
kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
unsigned int useroffset,
@@ -448,6 +460,10 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
if (!IS_ENABLED(CONFIG_SLAB_BUCKETS))
return ZERO_SIZE_PTR;
+ /* NULL makes kmalloc_slab() use the regular kmalloc caches. */
+ if (!slab_buckets_enabled)
+ return NULL;
+
if (WARN_ON(!kmem_buckets_cache))
return NULL;
@@ -1059,7 +1075,7 @@ void __init create_kmalloc_caches(void)
/* Kmalloc array is now usable */
slab_state = UP;
- if (IS_ENABLED(CONFIG_SLAB_BUCKETS))
+ if (IS_ENABLED(CONFIG_SLAB_BUCKETS) && slab_buckets_enabled)
kmem_buckets_cache = kmem_cache_create("kmalloc_buckets",
sizeof(kmem_buckets),
0, SLAB_NO_MERGE, NULL);
--
2.54.0