KMALLOC_PARTITION_CACHES creates several copies of each normal kmalloc cache and spreads allocations across them. That costs a fair bit of memory: Harry measured about 18 MiB more slab memory after boot on a 64 CPU, 64 GiB VM, mostly from under-used slabs [1]. Like SLAB_BUCKETS, it can only be chosen at build time. Add a kmalloc_partition= early parameter, enabled by default on kernels built with CONFIG_KMALLOC_PARTITION_CACHES=y. When it's off, the copies alias the normal caches rather than being created. Let's leave kmalloc_type() unchanged since each index simply resolves to the same cache when partitioning is off. Link: https://lore.kernel.org/r/179312451613.474906.1475329637924619088@kernel.org [1] Signed-off-by: Chris Down --- .../admin-guide/kernel-parameters.txt | 7 ++++++ mm/Kconfig | 5 ++++ mm/slab_common.c | 23 +++++++++++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index c27bbe205051..91caeef33c3a 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3045,6 +3045,13 @@ Kernel parameters Configure the RouterBoard 532 series on-chip Ethernet adapter MAC address. + kmalloc_partition= [MM,EARLY] + Format: + Enable or disable kmalloc cache partitioning on + kernels built with CONFIG_KMALLOC_PARTITION_CACHES=y. + Ignored without that option. + Default: on. + kmemleak= [KNL,EARLY] Boot-time kmemleak enable/disable Valid arguments: on, off Default: on diff --git a/mm/Kconfig b/mm/Kconfig index e602ebabd6e4..5bb6e33fab49 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -266,6 +266,11 @@ config KMALLOC_PARTITION_CACHES limited degree of memory and CPU overhead that relates to hardware and system workload. + The partitioning can be disabled at boot with the + "kmalloc_partition=0" kernel parameter, in which case the copies + are not created and all normal kmalloc allocations use the + regular kmalloc caches. + choice prompt "Partitioned slab cache mode" depends on KMALLOC_PARTITION_CACHES diff --git a/mm/slab_common.c b/mm/slab_common.c index 5575706b8938..20b066d61703 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -781,6 +781,17 @@ unsigned long random_kmalloc_seed __ro_after_init; EXPORT_SYMBOL(random_kmalloc_seed); #endif +static bool kmalloc_partition_enabled __ro_after_init = + IS_ENABLED(CONFIG_KMALLOC_PARTITION_CACHES); + +static int __init setup_kmalloc_partition(char *str) +{ + if (!IS_ENABLED(CONFIG_KMALLOC_PARTITION_CACHES)) + return 0; + return kstrtobool(str, &kmalloc_partition_enabled); +} +early_param("kmalloc_partition", setup_kmalloc_partition); + /* * Conversion table for small slabs sizes / 8 to the index in the * kmalloc array. This is necessary for slabs < 192 since we have non power @@ -1012,10 +1023,14 @@ new_kmalloc_cache(int idx, enum kmalloc_cache_type type) flags |= SLAB_CACHE_DMA; } -#ifdef CONFIG_KMALLOC_PARTITION_CACHES - if (type >= KMALLOC_PARTITION_START && type <= KMALLOC_PARTITION_END) - flags |= SLAB_NO_MERGE; -#endif + if (kmalloc_partition_enabled) { + if (type >= KMALLOC_PARTITION_START && type <= KMALLOC_PARTITION_END) + flags |= SLAB_NO_MERGE; + } else if (type > KMALLOC_PARTITION_START && type <= KMALLOC_PARTITION_END) { + /* Use the normal caches, which have already been created. */ + kmalloc_caches[type][idx] = kmalloc_caches[KMALLOC_NORMAL][idx]; + return; + } /* * If memcg_kmem is enabled and this is a KMALLOC_NORMAL cache and not -- 2.56.1