* [RFC PATCH 00/15] kmem_cache instances with static storage duration
@ 2026-01-10 4:02 Al Viro
2026-01-10 4:02 ` [RFC PATCH 01/15] static kmem_cache instances for core caches Al Viro
` (16 more replies)
0 siblings, 17 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
kmem_cache_create() and friends create new instances of
struct kmem_cache and return pointers to those. Quite a few things in
core kernel are allocated from such caches; each allocation involves
dereferencing an assign-once pointer and for sufficiently hot ones that
dereferencing does show in profiles.
There had been patches floating around switching some of those
to runtime_const infrastructure. Unfortunately, it's arch-specific
and most of the architectures lack it.
There's an alternative approach applicable at least to the caches
that are never destroyed, which covers a lot of them. No matter what,
runtime_const for pointers is not going to be faster than plain &,
so if we had struct kmem_cache instances with static storage duration, we
would be at least no worse off than we are with runtime_const variants.
There are obstacles to doing that, but they turn out to be easy
to deal with.
1) as it is, struct kmem_cache is opaque for anything outside of a few
files in mm/*; that avoids serious headache with header dependencies,
etc., and it's not something we want to lose. Solution: struct
kmem_cache_opaque, with the size and alignment identical to struct
kmem_cache. Calculation of size and alignment can be done via the same
mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
check for mismatches. With that done, we get an opaque type defined in
linux/slab-static.h that can be used for declaring those caches.
In linux/slab.h we add a forward declaration of kmem_cache_opaque +
helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
into pointer to kmem_cache.
2) real constructor of kmem_cache needs to be taught to deal with
preallocated instances. That turns out to be easy - we already pass an
obscene amount of optional arguments via struct kmem_cache_args, so we
can stash the pointer to preallocated instance in there. Changes in
mm/slab_common.c are very minor - we should treat preallocated caches
as unmergable, use the instance passed to us instead of allocating a
new one and we should not free them. That's it.
A set of helpers parallel to kmem_cache_create() and friends
(kmem_cache_setup(), etc.) is provided in the same linux/slab-static.h;
generally, conversion affects only a few lines.
Note that slab-static.h is needed only in places that create
such instances; all users need only slab.h (and they can be modular,
unlike runtime_const-based approach).
That covers the instances that never get destroyed. Quite a few
fall into that category, but there's a major exception - anything in
modules must be destroyed before the module gets removed. Note that
unlike runtime_constant-based approach, cache _uses_ in a module are
fine - if kmem_cache_opaque instance is exported, its address is available
to modules without any problems. It's caches _created_ in a module
that offer an extra twist.
Teaching kmem_cache_destroy() to skip actual freeing of given
kmem_cache instance is trivial; the problem is that kmem_cache_destroy()
may overlap with sysfs access to attributes of that cache. In that
case kmem_cache_destroy() may return before the instance gets freed -
freeing (from slab_kmem_cache_release()) happens when the refcount of
embedded kobject drops to zero. That's fine, since all references
to data structures in module's memory are already gone by the time
kmem_cache_destroy() returns. That, however, relies upon the struct
kmem_cache itself not being in module's memory; getting it unmapped
before slab_kmem_cache_release() has run needs to be avoided.
It's not hard to deal with, though. We need to make sure that
instance in a module will get to slab_kmem_cache_release() before the
module data gets freed. That's only a problem on sysfs setups -
otherwise it'll definitely be finished before kmem_cache_destroy()
returns.
Note that modules themselves have sysfs-exposed attributes,
so a similar problem already exists there. That's dealt with by
having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
reaching zero. Let's make use of that - have static-duration-in-module
kmem_cache instances grab a reference to that kobject upon setup and
drop it in the end of slab_kmem_cache_release().
Let setup helpers store the kobjetct to be pinned in
kmem_cache_args->owner (for preallocated; if somebody manually sets it
for non-preallocated case, it'll be ignored). That would be
&THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
If sysfs is enabled and we are dealing with preallocated instance,
let create_cache() grab and stash that reference in kmem_cache->owner
and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
instance.
Costs:
* a bit (SLAB_PREALLOCATED) is stolen from slab_flags_t
* such caches can't be merged. If you want them mergable, don't use that
technics.
* you can't do kmem_cache_setup()/kmem_cache_destroy()/kmem_cache_setup()
on the same instance. Just don't do that.
Al Viro (15):
static kmem_cache instances for core caches
allow static-duration kmem_cache in modules
make mnt_cache static-duration
turn thread_cache static-duration
turn signal_cache static-duration
turn bh_cachep static-duration
turn dentry_cache static-duration
turn files_cachep static-duration
make filp and bfilp caches static-duration
turn sighand_cache static-duration
turn mm_cachep static-duration
turn task_struct_cachep static-duration
turn fs_cachep static-duration
turn inode_cachep static-duration
turn ufs_inode_cache static-duration
Kbuild | 13 +++++-
fs/buffer.c | 6 ++-
fs/dcache.c | 8 ++--
fs/file_table.c | 32 +++++++-------
fs/inode.c | 6 ++-
fs/namespace.c | 6 ++-
fs/ufs/super.c | 9 ++--
include/asm-generic/vmlinux.lds.h | 3 +-
include/linux/fdtable.h | 3 +-
include/linux/fs_struct.h | 3 +-
include/linux/signal.h | 3 +-
include/linux/slab-static.h | 69 +++++++++++++++++++++++++++++++
include/linux/slab.h | 11 +++++
kernel/fork.c | 37 ++++++++++-------
mm/kmem_cache_size.c | 20 +++++++++
mm/slab.h | 1 +
mm/slab_common.c | 44 +++++++++++++-------
mm/slub.c | 7 ++++
18 files changed, 214 insertions(+), 67 deletions(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
--
2.47.3
^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 5:40 ` Matthew Wilcox
2026-01-14 7:30 ` Harry Yoo
2026-01-10 4:02 ` [RFC PATCH 02/15] allow static-duration kmem_cache in modules Al Viro
` (15 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
kmem_cache_create() and friends create new instances of
struct kmem_cache and return pointers to those. Quite a few things in
core kernel are allocated from such caches; each allocation involves
dereferencing an assign-once pointer and for sufficiently hot ones that
dereferencing does show in profiles.
There had been patches floating around switching some of those
to runtime_const infrastructure. Unfortunately, it's arch-specific
and most of the architectures lack it.
There's an alternative approach applicable at least to the caches
that are never destroyed, which covers a lot of them. No matter what,
runtime_const for pointers is not going to be faster than plain &,
so if we had struct kmem_cache instances with static storage duration, we
would be at least no worse off than we are with runtime_const variants.
There are obstacles to doing that, but they turn out to be easy
to deal with.
1) as it is, struct kmem_cache is opaque for anything outside of a few
files in mm/*; that avoids serious headache with header dependencies,
etc., and it's not something we want to lose. Solution: struct
kmem_cache_opaque, with the size and alignment identical to struct
kmem_cache. Calculation of size and alignment can be done via the same
mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
check for mismatches. With that done, we get an opaque type defined in
linux/slab-static.h that can be used for declaring those caches.
In linux/slab.h we add a forward declaration of kmem_cache_opaque +
helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
into pointer to kmem_cache.
2) real constructor of kmem_cache needs to be taught to deal with
preallocated instances. That turns out to be easy - we already pass an
obscene amount of optional arguments via struct kmem_cache_args, so we
can stash the pointer to preallocated instance in there. Changes in
mm/slab_common.c are very minor - we should treat preallocated caches
as unmergable, use the instance passed to us instead of allocating a
new one and we should not free them. That's it.
Note that slab-static.h is needed only in places that create
such instances; all users need only slab.h (and they can be modular,
unlike runtime_const-based approach).
That covers the instances that never get destroyed. Quite a few
fall into that category, but there's a major exception - anything in
modules must be destroyed before the module gets removed. For example,
filesystems that have their inodes allocated from a private kmem_cache
can't make use of that technics for their inode allocations, etc.
It's not that hard to deal with, but for now let's just ban
including slab-static.h from modules.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Kbuild | 13 +++++++-
include/linux/slab-static.h | 65 +++++++++++++++++++++++++++++++++++++
include/linux/slab.h | 7 ++++
mm/kmem_cache_size.c | 20 ++++++++++++
mm/slab_common.c | 30 ++++++++---------
mm/slub.c | 7 ++++
6 files changed, 126 insertions(+), 16 deletions(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
diff --git a/Kbuild b/Kbuild
index 13324b4bbe23..eb985a6614eb 100644
--- a/Kbuild
+++ b/Kbuild
@@ -45,13 +45,24 @@ kernel/sched/rq-offsets.s: $(offsets-file)
$(rq-offsets-file): kernel/sched/rq-offsets.s FORCE
$(call filechk,offsets,__RQ_OFFSETS_H__)
+# generate kmem_cache_size.h
+
+kmem_cache_size-file := include/generated/kmem_cache_size.h
+
+targets += mm/kmem_cache_size.s
+
+mm/kmem_cache_size.s: $(rq-offsets-file)
+
+$(kmem_cache_size-file): mm/kmem_cache_size.s FORCE
+ $(call filechk,offsets,__KMEM_CACHE_SIZE_H__)
+
# Check for missing system calls
quiet_cmd_syscalls = CALL $<
cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags) $(missing_syscalls_flags)
PHONY += missing-syscalls
-missing-syscalls: scripts/checksyscalls.sh $(rq-offsets-file)
+missing-syscalls: scripts/checksyscalls.sh $(kmem_cache_size-file)
$(call cmd,syscalls)
# Check the manual modification of atomic headers
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
new file mode 100644
index 000000000000..47b2220b4988
--- /dev/null
+++ b/include/linux/slab-static.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SLAB_STATIC_H
+#define _LINUX_SLAB_STATIC_H
+
+#ifdef MODULE
+#error "can't use that in modules"
+#endif
+
+#include <generated/kmem_cache_size.h>
+
+/* same size and alignment as struct kmem_cache: */
+struct kmem_cache_opaque {
+ unsigned char opaque[KMEM_CACHE_SIZE];
+} __aligned(KMEM_CACHE_ALIGN);
+
+#define __KMEM_CACHE_SETUP(cache, name, size, flags, ...) \
+ __kmem_cache_create_args((name), (size), \
+ &(struct kmem_cache_args) { \
+ .preallocated = (cache), \
+ __VA_ARGS__}, (flags))
+
+static inline int
+kmem_cache_setup_usercopy(struct kmem_cache *s,
+ const char *name, unsigned int size,
+ unsigned int align, slab_flags_t flags,
+ unsigned int useroffset, unsigned int usersize,
+ void (*ctor)(void *))
+{
+ struct kmem_cache *res;
+ res = __KMEM_CACHE_SETUP(s, name, size, flags,
+ .align = align,
+ .ctor = ctor,
+ .useroffset = useroffset,
+ .usersize = usersize);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+ return 0;
+}
+
+static inline int
+kmem_cache_setup(struct kmem_cache *s,
+ const char *name, unsigned int size,
+ unsigned int align, slab_flags_t flags,
+ void (*ctor)(void *))
+{
+ struct kmem_cache *res;
+ res = __KMEM_CACHE_SETUP(s, name, size, flags,
+ .align = align,
+ .ctor = ctor);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+ return 0;
+}
+
+#define KMEM_CACHE_SETUP(s, __struct, __flags) \
+ __KMEM_CACHE_SETUP((s), #__struct, sizeof(struct __struct), (__flags), \
+ .align = __alignof__(struct __struct))
+
+#define KMEM_CACHE_SETUP_USERCOPY(s, __struct, __flags, __field) \
+ __KMEM_CACHE_SETUP((s), #__struct, sizeof(struct __struct), (__flags), \
+ .align = __alignof__(struct __struct), \
+ .useroffset = offsetof(struct __struct, __field), \
+ .usersize = sizeof_field(struct __struct, __field))
+
+#endif
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2482992248dc..f16c784148b4 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -261,11 +261,17 @@ enum _slab_flag_bits {
struct list_lru;
struct mem_cgroup;
+struct kmem_cache_opaque;
/*
* struct kmem_cache related prototypes
*/
bool slab_is_available(void);
+static inline struct kmem_cache *to_kmem_cache(struct kmem_cache_opaque *p)
+{
+ return (struct kmem_cache *)p;
+}
+
/**
* struct kmem_cache_args - Less common arguments for kmem_cache_create()
*
@@ -366,6 +372,7 @@ struct kmem_cache_args {
* %0 means no sheaves will be created.
*/
unsigned int sheaf_capacity;
+ struct kmem_cache *preallocated;
};
struct kmem_cache *__kmem_cache_create_args(const char *name,
diff --git a/mm/kmem_cache_size.c b/mm/kmem_cache_size.c
new file mode 100644
index 000000000000..1ddbfa41a507
--- /dev/null
+++ b/mm/kmem_cache_size.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generate definitions needed by the preprocessor.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#define COMPILE_OFFSETS
+#include <linux/kbuild.h>
+#include "slab.h"
+
+int main(void)
+{
+ /* The constants to put into include/generated/kmem_cache_size.h */
+ DEFINE(KMEM_CACHE_SIZE, sizeof(struct kmem_cache));
+ DEFINE(KMEM_CACHE_ALIGN, __alignof(struct kmem_cache));
+ /* End of constants */
+
+ return 0;
+}
diff --git a/mm/slab_common.c b/mm/slab_common.c
index eed7ea556cb1..81a413b44afb 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -224,33 +224,30 @@ static struct kmem_cache *create_cache(const char *name,
struct kmem_cache_args *args,
slab_flags_t flags)
{
- struct kmem_cache *s;
+ struct kmem_cache *s = args->preallocated;
int err;
/* If a custom freelist pointer is requested make sure it's sane. */
- err = -EINVAL;
if (args->use_freeptr_offset &&
(args->freeptr_offset >= object_size ||
!(flags & SLAB_TYPESAFE_BY_RCU) ||
!IS_ALIGNED(args->freeptr_offset, __alignof__(freeptr_t))))
- goto out;
+ return ERR_PTR(-EINVAL);
- err = -ENOMEM;
- s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
- if (!s)
- goto out;
+ if (!s) {
+ s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
+ if (!s)
+ return ERR_PTR(-ENOMEM);
+ }
err = do_kmem_cache_create(s, name, object_size, args, flags);
- if (err)
- goto out_free_cache;
-
+ if (unlikely(err)) {
+ if (!args->preallocated)
+ kmem_cache_free(kmem_cache, s);
+ return ERR_PTR(err);
+ }
s->refcount = 1;
list_add(&s->list, &slab_caches);
return s;
-
-out_free_cache:
- kmem_cache_free(kmem_cache, s);
-out:
- return ERR_PTR(err);
}
/**
@@ -324,6 +321,9 @@ struct kmem_cache *__kmem_cache_create_args(const char *name,
object_size - args->usersize < args->useroffset))
args->usersize = args->useroffset = 0;
+ if (args->preallocated)
+ flags |= SLAB_NO_MERGE;
+
if (!args->usersize && !args->sheaf_capacity)
s = __kmem_cache_alias(name, object_size, args->align, flags,
args->ctor);
diff --git a/mm/slub.c b/mm/slub.c
index 861592ac5425..41fe79b3f055 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -47,6 +47,7 @@
#include <linux/irq_work.h>
#include <linux/kprobes.h>
#include <linux/debugfs.h>
+#include <linux/slab-static.h>
#include <trace/events/kmem.h>
#include "internal.h"
@@ -8491,6 +8492,12 @@ void __init kmem_cache_init(void)
boot_kmem_cache_node;
int node;
+ /* verify that kmem_cache_opaque is correct */
+ BUILD_BUG_ON(sizeof(struct kmem_cache) !=
+ sizeof(struct kmem_cache_opaque));
+ BUILD_BUG_ON(__alignof(struct kmem_cache) !=
+ __alignof(struct kmem_cache_opaque));
+
if (debug_guardpage_minorder())
slub_max_order = 0;
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 02/15] allow static-duration kmem_cache in modules
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 01/15] static kmem_cache instances for core caches Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 03/15] make mnt_cache static-duration Al Viro
` (14 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
We need to make sure that instance in a module will get to
slab_kmem_cache_release() before the module data gets freed. That's only
a problem on sysfs setups - otherwise it'll definitely be finished before
kmem_cache_destroy() returns.
Note that modules themselves have sysfs-exposed attributes,
so a similar problem already exists there. That's dealt with by
having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
reaching zero. Let's make use of that - have static-duration-in-module
kmem_cache instances grab a reference to that kobject upon setup and
drop it in the end of slab_kmem_cache_release().
Let setup helpers store the kobjetct to be pinned in
kmem_cache_args->owner (for preallocated; if somebody manually sets it
for non-preallocated case, it'll be ignored). That would be
&THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
If sysfs is enabled and we are dealing with preallocated instance,
let create_cache() grab and stash that reference in kmem_cache->owner
and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
instance.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/slab-static.h | 12 ++++++++----
include/linux/slab.h | 4 ++++
mm/slab.h | 1 +
mm/slab_common.c | 16 ++++++++++++++--
4 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
index 47b2220b4988..16d1564b4a4b 100644
--- a/include/linux/slab-static.h
+++ b/include/linux/slab-static.h
@@ -2,10 +2,7 @@
#ifndef _LINUX_SLAB_STATIC_H
#define _LINUX_SLAB_STATIC_H
-#ifdef MODULE
-#error "can't use that in modules"
-#endif
-
+#include <linux/init.h>
#include <generated/kmem_cache_size.h>
/* same size and alignment as struct kmem_cache: */
@@ -13,9 +10,16 @@ struct kmem_cache_opaque {
unsigned char opaque[KMEM_CACHE_SIZE];
} __aligned(KMEM_CACHE_ALIGN);
+#ifdef MODULE
+#define THIS_MODULE_KOBJ &THIS_MODULE->mkobj.kobj
+#else
+#define THIS_MODULE_KOBJ NULL
+#endif
+
#define __KMEM_CACHE_SETUP(cache, name, size, flags, ...) \
__kmem_cache_create_args((name), (size), \
&(struct kmem_cache_args) { \
+ .owner = THIS_MODULE_KOBJ, \
.preallocated = (cache), \
__VA_ARGS__}, (flags))
diff --git a/include/linux/slab.h b/include/linux/slab.h
index f16c784148b4..dc1aeb14a12b 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -60,6 +60,7 @@ enum _slab_flag_bits {
#ifdef CONFIG_SLAB_OBJ_EXT
_SLAB_NO_OBJ_EXT,
#endif
+ _SLAB_PREALLOCATED,
_SLAB_FLAGS_LAST_BIT
};
@@ -244,6 +245,8 @@ enum _slab_flag_bits {
#define SLAB_NO_OBJ_EXT __SLAB_FLAG_UNUSED
#endif
+#define SLAB_PREALLOCATED __SLAB_FLAG_BIT(_SLAB_PREALLOCATED)
+
/*
* ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
*
@@ -373,6 +376,7 @@ struct kmem_cache_args {
*/
unsigned int sheaf_capacity;
struct kmem_cache *preallocated;
+ struct kobject *owner;
};
struct kmem_cache *__kmem_cache_create_args(const char *name,
diff --git a/mm/slab.h b/mm/slab.h
index e767aa7e91b0..9ff9a0a3b164 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -249,6 +249,7 @@ struct kmem_cache {
struct list_head list; /* List of slab caches */
#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
+ struct kobject *owner; /* keep that pinned while alive */
#endif
#ifdef CONFIG_SLAB_FREELIST_HARDENED
unsigned long random;
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 81a413b44afb..a854e6872acd 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -245,6 +245,12 @@ static struct kmem_cache *create_cache(const char *name,
kmem_cache_free(kmem_cache, s);
return ERR_PTR(err);
}
+#ifdef CONFIG_SYSFS
+ if (flags & SLAB_PREALLOCATED) {
+ s->owner = args->owner;
+ kobject_get(s->owner);
+ }
+#endif
s->refcount = 1;
list_add(&s->list, &slab_caches);
return s;
@@ -322,7 +328,7 @@ struct kmem_cache *__kmem_cache_create_args(const char *name,
args->usersize = args->useroffset = 0;
if (args->preallocated)
- flags |= SLAB_NO_MERGE;
+ flags |= SLAB_NO_MERGE | SLAB_PREALLOCATED;
if (!args->usersize && !args->sheaf_capacity)
s = __kmem_cache_alias(name, object_size, args->align, flags,
@@ -481,7 +487,13 @@ void slab_kmem_cache_release(struct kmem_cache *s)
{
__kmem_cache_release(s);
kfree_const(s->name);
- kmem_cache_free(kmem_cache, s);
+ if (!(s->flags & SLAB_PREALLOCATED)) {
+ kmem_cache_free(kmem_cache, s);
+ return;
+ }
+#ifdef CONFIG_SYSFS
+ kobject_put(s->owner);
+#endif
}
void kmem_cache_destroy(struct kmem_cache *s)
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 03/15] make mnt_cache static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 01/15] static kmem_cache instances for core caches Al Viro
2026-01-10 4:02 ` [RFC PATCH 02/15] allow static-duration kmem_cache in modules Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 04/15] turn thread_cache static-duration Al Viro
` (13 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index c58674a20cad..9a9882df463d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -34,6 +34,7 @@
#include <linux/mnt_idmapping.h>
#include <linux/pidfs.h>
#include <linux/nstree.h>
+#include <linux/slab-static.h>
#include "pnode.h"
#include "internal.h"
@@ -85,7 +86,8 @@ static u64 mnt_id_ctr = MNT_UNIQUE_ID_OFFSET;
static struct hlist_head *mount_hashtable __ro_after_init;
static struct hlist_head *mountpoint_hashtable __ro_after_init;
-static struct kmem_cache *mnt_cache __ro_after_init;
+static struct kmem_cache_opaque __mnt_cache;
+#define mnt_cache to_kmem_cache(&__mnt_cache)
static DECLARE_RWSEM(namespace_sem);
static HLIST_HEAD(unmounted); /* protected by namespace_sem */
static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
@@ -5997,7 +5999,7 @@ void __init mnt_init(void)
{
int err;
- mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
+ kmem_cache_setup(mnt_cache, "mnt_cache", sizeof(struct mount),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
mount_hashtable = alloc_large_system_hash("Mount-cache",
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 04/15] turn thread_cache static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (2 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 03/15] make mnt_cache static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 05/15] turn signal_cache static-duration Al Viro
` (12 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
... and make is SLAB_PANIC instead of simulating it with BUG_ON() -
the boot is not going to get to kernel threads, nevermind userland...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
kernel/fork.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/kernel/fork.c b/kernel/fork.c
index b1f3915d5f8e..ddd2558f9431 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -108,6 +108,7 @@
#include <linux/unwind_deferred.h>
#include <linux/pgalloc.h>
#include <linux/uaccess.h>
+#include <linux/slab-static.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -422,7 +423,8 @@ static void free_thread_stack(struct task_struct *tsk)
#else /* !(THREAD_SIZE >= PAGE_SIZE) */
-static struct kmem_cache *thread_stack_cache;
+static struct kmem_cache_opaque __thread_stack_cache;
+#define thread_stack_cache to_kmem_cache(&__thread_stack_cache)
static void thread_stack_free_rcu(struct rcu_head *rh)
{
@@ -453,10 +455,10 @@ static void free_thread_stack(struct task_struct *tsk)
void thread_stack_cache_init(void)
{
- thread_stack_cache = kmem_cache_create_usercopy("thread_stack",
- THREAD_SIZE, THREAD_SIZE, 0, 0,
+ kmem_cache_setup_usercopy(thread_stack_cache, "thread_stack",
+ THREAD_SIZE, THREAD_SIZE,
+ SLAB_PANIC, 0,
THREAD_SIZE, NULL);
- BUG_ON(thread_stack_cache == NULL);
}
#endif /* THREAD_SIZE >= PAGE_SIZE */
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 05/15] turn signal_cache static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (3 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 04/15] turn thread_cache static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 06/15] turn bh_cachep static-duration Al Viro
` (11 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
kernel/fork.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/fork.c b/kernel/fork.c
index ddd2558f9431..23ed80d0d6d0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -465,7 +465,8 @@ void thread_stack_cache_init(void)
#endif /* CONFIG_VMAP_STACK */
/* SLAB cache for signal_struct structures (tsk->signal) */
-static struct kmem_cache *signal_cachep;
+static struct kmem_cache_opaque signal_cache;
+#define signal_cachep to_kmem_cache(&signal_cache)
/* SLAB cache for sighand_struct structures (tsk->sighand) */
struct kmem_cache *sighand_cachep;
@@ -3024,7 +3025,7 @@ void __init proc_caches_init(void)
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU|
SLAB_ACCOUNT, sighand_ctor);
- signal_cachep = kmem_cache_create("signal_cache",
+ kmem_cache_setup(signal_cachep, "signal_cache",
sizeof(struct signal_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 06/15] turn bh_cachep static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (4 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 05/15] turn signal_cache static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 07/15] turn dentry_cache static-duration Al Viro
` (10 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/buffer.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 838c0c571022..c8ec1b440880 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -50,6 +50,7 @@
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/sched/isolation.h>
+#include <linux/slab-static.h>
#include "internal.h"
@@ -2990,7 +2991,8 @@ EXPORT_SYMBOL(try_to_free_buffers);
/*
* Buffer-head allocation
*/
-static struct kmem_cache *bh_cachep __ro_after_init;
+static struct kmem_cache_opaque bh_cache;
+#define bh_cachep to_kmem_cache(&bh_cache)
/*
* Once the number of bh's in the machine exceeds this level, we start
@@ -3149,7 +3151,7 @@ void __init buffer_init(void)
unsigned long nrpages;
int ret;
- bh_cachep = KMEM_CACHE(buffer_head,
+ KMEM_CACHE_SETUP(bh_cachep, buffer_head,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC);
/*
* Limit the bh occupancy to 10% of ZONE_NORMAL
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 07/15] turn dentry_cache static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (5 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 06/15] turn bh_cachep static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 08/15] turn files_cachep static-duration Al Viro
` (9 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
No need to bother with runtime_const() for it anymore...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 8 ++++----
include/asm-generic/vmlinux.lds.h | 3 +--
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index dc2fff4811d1..43d3b4fbedcc 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -32,6 +32,7 @@
#include <linux/bit_spinlock.h>
#include <linux/rculist_bl.h>
#include <linux/list_lru.h>
+#include <linux/slab-static.h>
#include "internal.h"
#include "mount.h"
@@ -86,8 +87,8 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
EXPORT_SYMBOL(rename_lock);
-static struct kmem_cache *__dentry_cache __ro_after_init;
-#define dentry_cache runtime_const_ptr(__dentry_cache)
+static struct kmem_cache_opaque __dentry_cache;
+#define dentry_cache to_kmem_cache(&__dentry_cache)
const struct qstr empty_name = QSTR_INIT("", 0);
EXPORT_SYMBOL(empty_name);
@@ -3265,10 +3266,9 @@ static void __init dcache_init(void)
* but it is probably not worth it because of the cache nature
* of the dcache.
*/
- __dentry_cache = KMEM_CACHE_USERCOPY(dentry,
+ KMEM_CACHE_SETUP_USERCOPY(dentry_cache, dentry,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_ACCOUNT,
d_shortname.string);
- runtime_const_init(ptr, __dentry_cache);
/* Hash may have been set up in dcache_init_early */
if (!hashdist)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8ca130af301f..6997f6301260 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -971,8 +971,7 @@
#define RUNTIME_CONST_VARIABLES \
RUNTIME_CONST(shift, d_hash_shift) \
- RUNTIME_CONST(ptr, dentry_hashtable) \
- RUNTIME_CONST(ptr, __dentry_cache)
+ RUNTIME_CONST(ptr, dentry_hashtable)
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
#define KUNIT_TABLE() \
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 08/15] turn files_cachep static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (6 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 07/15] turn dentry_cache static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 09/15] make filp and bfilp caches static-duration Al Viro
` (8 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/fdtable.h | 3 ++-
kernel/fork.c | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index c45306a9f007..f2d553f99c58 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -113,6 +113,7 @@ int iterate_fd(struct files_struct *, unsigned,
extern int close_fd(unsigned int fd);
extern struct file *file_close_fd(unsigned int fd);
-extern struct kmem_cache *files_cachep;
+extern struct kmem_cache_opaque files_cache;
+#define files_cachep to_kmem_cache(&files_cache)
#endif /* __LINUX_FDTABLE_H */
diff --git a/kernel/fork.c b/kernel/fork.c
index 23ed80d0d6d0..8c4d9a81ef42 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -472,7 +472,7 @@ static struct kmem_cache_opaque signal_cache;
struct kmem_cache *sighand_cachep;
/* SLAB cache for files_struct structures (tsk->files) */
-struct kmem_cache *files_cachep;
+struct kmem_cache_opaque files_cache;
/* SLAB cache for fs_struct structures (tsk->fs) */
struct kmem_cache *fs_cachep;
@@ -3029,7 +3029,7 @@ void __init proc_caches_init(void)
sizeof(struct signal_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
- files_cachep = kmem_cache_create("files_cache",
+ kmem_cache_setup(files_cachep, "files_cache",
sizeof(struct files_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 09/15] make filp and bfilp caches static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (7 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 08/15] turn files_cachep static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 10/15] turn sighand_cache static-duration Al Viro
` (7 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
As much as I hate it, the name "filp" is a part of userland ABI at this
point - scripts grepping for it in /proc/slabinfo do exist ;-/
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/file_table.c | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/fs/file_table.c b/fs/file_table.c
index cd4a3db4659a..18a992b40109 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -27,6 +27,7 @@
#include <linux/task_work.h>
#include <linux/swap.h>
#include <linux/kmemleak.h>
+#include <linux/slab-static.h>
#include <linux/atomic.h>
@@ -38,8 +39,10 @@ static struct files_stat_struct files_stat = {
};
/* SLAB cache for file structures */
-static struct kmem_cache *filp_cachep __ro_after_init;
-static struct kmem_cache *bfilp_cachep __ro_after_init;
+static struct kmem_cache_opaque file_cache;
+static struct kmem_cache_opaque backing_file_cache;
+#define filp_cachep to_kmem_cache(&file_cache)
+#define bfilp_cachep to_kmem_cache(&backing_file_cache)
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
@@ -587,19 +590,20 @@ void fput_close(struct file *file)
void __init files_init(void)
{
- struct kmem_cache_args args = {
- .use_freeptr_offset = true,
- .freeptr_offset = offsetof(struct file, f_freeptr),
- };
-
- filp_cachep = kmem_cache_create("filp", sizeof(struct file), &args,
- SLAB_HWCACHE_ALIGN | SLAB_PANIC |
- SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU);
+ __KMEM_CACHE_SETUP(filp_cachep, "filp", sizeof(struct file),
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+ SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
+ .use_freeptr_offset = true,
+ .freeptr_offset = offsetof(struct file,
+ f_freeptr));
+
+ __KMEM_CACHE_SETUP(bfilp_cachep, "bfilp", sizeof(struct backing_file),
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+ SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
+ .use_freeptr_offset = true,
+ .freeptr_offset = offsetof(struct backing_file,
+ bf_freeptr));
- args.freeptr_offset = offsetof(struct backing_file, bf_freeptr);
- bfilp_cachep = kmem_cache_create("bfilp", sizeof(struct backing_file),
- &args, SLAB_HWCACHE_ALIGN | SLAB_PANIC |
- SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU);
percpu_counter_init(&nr_files, 0, GFP_KERNEL);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 10/15] turn sighand_cache static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (8 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 09/15] make filp and bfilp caches static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 11/15] turn mm_cachep static-duration Al Viro
` (6 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/signal.h | 3 ++-
kernel/fork.c | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/linux/signal.h b/include/linux/signal.h
index f19816832f05..a0c7fee8b22a 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -323,7 +323,8 @@ static inline void disallow_signal(int sig)
kernel_sigaction(sig, SIG_IGN);
}
-extern struct kmem_cache *sighand_cachep;
+extern struct kmem_cache_opaque sighand_cache;
+#define sighand_cachep to_kmem_cache(&sighand_cache)
extern bool unhandled_signal(struct task_struct *tsk, int sig);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8c4d9a81ef42..d5b7e4d51596 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -469,7 +469,7 @@ static struct kmem_cache_opaque signal_cache;
#define signal_cachep to_kmem_cache(&signal_cache)
/* SLAB cache for sighand_struct structures (tsk->sighand) */
-struct kmem_cache *sighand_cachep;
+struct kmem_cache_opaque sighand_cache;
/* SLAB cache for files_struct structures (tsk->files) */
struct kmem_cache_opaque files_cache;
@@ -3021,7 +3021,7 @@ void __init mm_cache_init(void)
void __init proc_caches_init(void)
{
- sighand_cachep = kmem_cache_create("sighand_cache",
+ kmem_cache_setup(sighand_cachep, "sighand_cache",
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU|
SLAB_ACCOUNT, sighand_ctor);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 11/15] turn mm_cachep static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (9 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 10/15] turn sighand_cache static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 12/15] turn task_struct_cachep static-duration Al Viro
` (5 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
kernel/fork.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/fork.c b/kernel/fork.c
index d5b7e4d51596..f83ca2f5826f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -478,7 +478,8 @@ struct kmem_cache_opaque files_cache;
struct kmem_cache *fs_cachep;
/* SLAB cache for mm_struct structures (tsk->mm) */
-static struct kmem_cache *mm_cachep;
+static struct kmem_cache_opaque mm_cache;
+#define mm_cachep to_kmem_cache(&mm_cache)
static void account_kernel_stack(struct task_struct *tsk, int account)
{
@@ -3011,7 +3012,7 @@ void __init mm_cache_init(void)
*/
mm_size = sizeof(struct mm_struct) + cpumask_size() + mm_cid_size();
- mm_cachep = kmem_cache_create_usercopy("mm_struct",
+ kmem_cache_setup_usercopy(mm_cachep, "mm_struct",
mm_size, ARCH_MIN_MMSTRUCT_ALIGN,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
offsetof(struct mm_struct, saved_auxv),
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 12/15] turn task_struct_cachep static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (10 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 11/15] turn mm_cachep static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 13/15] turn fs_cachep static-duration Al Viro
` (4 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
kernel/fork.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/fork.c b/kernel/fork.c
index f83ca2f5826f..8f0dfefd82f0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -178,7 +178,8 @@ void __weak arch_release_task_struct(struct task_struct *tsk)
{
}
-static struct kmem_cache *task_struct_cachep;
+static struct kmem_cache_opaque task_struct_cache;
+#define task_struct_cachep to_kmem_cache(&task_struct_cache)
static inline struct task_struct *alloc_task_struct_node(int node)
{
@@ -860,7 +861,7 @@ void __init fork_init(void)
/* create a slab on which task_structs can be allocated */
task_struct_whitelist(&useroffset, &usersize);
- task_struct_cachep = kmem_cache_create_usercopy("task_struct",
+ kmem_cache_setup_usercopy(task_struct_cachep, "task_struct",
arch_task_struct_size, align,
SLAB_PANIC|SLAB_ACCOUNT,
useroffset, usersize, NULL);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 13/15] turn fs_cachep static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (11 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 12/15] turn task_struct_cachep static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 14/15] turn inode_cachep static-duration Al Viro
` (3 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/fs_struct.h | 3 ++-
kernel/fork.c | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 0070764b790a..e8c9fac5b7b7 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -15,7 +15,8 @@ struct fs_struct {
struct path root, pwd;
} __randomize_layout;
-extern struct kmem_cache *fs_cachep;
+extern struct kmem_cache_opaque fs_struct_cache;
+#define fs_cachep to_kmem_cache(&fs_struct_cache)
extern void exit_fs(struct task_struct *);
extern void set_fs_root(struct fs_struct *, const struct path *);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8f0dfefd82f0..7262abd0d2a4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -476,7 +476,7 @@ struct kmem_cache_opaque sighand_cache;
struct kmem_cache_opaque files_cache;
/* SLAB cache for fs_struct structures (tsk->fs) */
-struct kmem_cache *fs_cachep;
+struct kmem_cache_opaque fs_struct_cache;
/* SLAB cache for mm_struct structures (tsk->mm) */
static struct kmem_cache_opaque mm_cache;
@@ -3035,7 +3035,7 @@ void __init proc_caches_init(void)
sizeof(struct files_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
- fs_cachep = kmem_cache_create("fs_cache",
+ kmem_cache_setup(fs_cachep, "fs_cache",
sizeof(struct fs_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 14/15] turn inode_cachep static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (12 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 13/15] turn fs_cachep static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 15/15] turn ufs_inode_cache static-duration Al Viro
` (2 subsequent siblings)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/inode.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 521383223d8a..7c212696ba67 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -23,6 +23,7 @@
#include <linux/rw_hint.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/slab-static.h>
#include <trace/events/writeback.h>
#define CREATE_TRACE_POINTS
#include <trace/events/timestamp.h>
@@ -76,7 +77,8 @@ EXPORT_SYMBOL(empty_aops);
static DEFINE_PER_CPU(unsigned long, nr_inodes);
static DEFINE_PER_CPU(unsigned long, nr_unused);
-static struct kmem_cache *inode_cachep __ro_after_init;
+static struct kmem_cache_opaque inode_cache;
+#define inode_cachep to_kmem_cache(&inode_cache)
static long get_nr_inodes(void)
{
@@ -2564,7 +2566,7 @@ void __init inode_init_early(void)
void __init inode_init(void)
{
/* inode slab cache */
- inode_cachep = kmem_cache_create("inode_cache",
+ kmem_cache_setup(inode_cachep, "inode_cache",
sizeof(struct inode),
0,
(SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH 15/15] turn ufs_inode_cache static-duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (13 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 14/15] turn inode_cachep static-duration Al Viro
@ 2026-01-10 4:02 ` Al Viro
2026-01-10 5:33 ` [RFC PATCH 00/15] kmem_cache instances with static storage duration Linus Torvalds
2026-01-15 0:46 ` Christoph Lameter (Ampere)
16 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 4:02 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
A modular example I used for testing...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/super.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 6e4585169f94..440229a5b6c9 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -90,6 +90,7 @@
#include <linux/log2.h>
#include <linux/seq_file.h>
#include <linux/iversion.h>
+#include <linux/slab-static.h>
#include "ufs_fs.h"
#include "ufs.h"
@@ -1354,7 +1355,8 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static struct kmem_cache * ufs_inode_cachep;
+static struct kmem_cache_opaque ufs_inode_cache;
+#define ufs_inode_cachep to_kmem_cache(&ufs_inode_cache)
static struct inode *ufs_alloc_inode(struct super_block *sb)
{
@@ -1384,16 +1386,13 @@ static void init_once(void *foo)
static int __init init_inodecache(void)
{
- ufs_inode_cachep = kmem_cache_create_usercopy("ufs_inode_cache",
+ return kmem_cache_setup_usercopy(ufs_inode_cachep, "ufs_inode_cache",
sizeof(struct ufs_inode_info), 0,
(SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT),
offsetof(struct ufs_inode_info, i_u1.i_symlink),
sizeof_field(struct ufs_inode_info,
i_u1.i_symlink),
init_once);
- if (ufs_inode_cachep == NULL)
- return -ENOMEM;
- return 0;
}
static void destroy_inodecache(void)
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (14 preceding siblings ...)
2026-01-10 4:02 ` [RFC PATCH 15/15] turn ufs_inode_cache static-duration Al Viro
@ 2026-01-10 5:33 ` Linus Torvalds
2026-01-10 6:16 ` Al Viro
2026-01-15 0:46 ` Christoph Lameter (Ampere)
16 siblings, 1 reply; 52+ messages in thread
From: Linus Torvalds @ 2026-01-10 5:33 UTC (permalink / raw)
To: Al Viro
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
On Fri, 9 Jan 2026 at 18:01, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> There's an alternative approach applicable at least to the caches
> that are never destroyed, which covers a lot of them. No matter what,
> runtime_const for pointers is not going to be faster than plain &,
> so if we had struct kmem_cache instances with static storage duration, we
> would be at least no worse off than we are with runtime_const variants.
I like it. Much better than runtime_const for these things.
That said, I don't love the commit messages. "turn xyzzy
static-duration" reads very oddly to me, and because I saw the emails
out of order originally it just made me go "whaa?"
So can we please explain this some more obvious way. Maybe just "Make
xyz be statically allocated". Yes, I'm nitpicking, but I feel like
explaining core patches is worth the effort.
And maybe that's for the sad reason that I read more explanations than
code these days '/
Linus
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-10 4:02 ` [RFC PATCH 01/15] static kmem_cache instances for core caches Al Viro
@ 2026-01-10 5:40 ` Matthew Wilcox
2026-01-10 6:23 ` Al Viro
2026-01-14 7:30 ` Harry Yoo
1 sibling, 1 reply; 52+ messages in thread
From: Matthew Wilcox @ 2026-01-10 5:40 UTC (permalink / raw)
To: Al Viro
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Sat, Jan 10, 2026 at 04:02:03AM +0000, Al Viro wrote:
> +++ b/Kbuild
> @@ -45,13 +45,24 @@ kernel/sched/rq-offsets.s: $(offsets-file)
> $(rq-offsets-file): kernel/sched/rq-offsets.s FORCE
> $(call filechk,offsets,__RQ_OFFSETS_H__)
>
> +# generate kmem_cache_size.h
> +
> +kmem_cache_size-file := include/generated/kmem_cache_size.h
> +
> +targets += mm/kmem_cache_size.s
> +
> +mm/kmem_cache_size.s: $(rq-offsets-file)
> +
> +$(kmem_cache_size-file): mm/kmem_cache_size.s FORCE
> + $(call filechk,offsets,__KMEM_CACHE_SIZE_H__)
> +
> # Check for missing system calls
>
> quiet_cmd_syscalls = CALL $<
> cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags) $(missing_syscalls_flags)
>
> PHONY += missing-syscalls
> -missing-syscalls: scripts/checksyscalls.sh $(rq-offsets-file)
> +missing-syscalls: scripts/checksyscalls.sh $(kmem_cache_size-file)
> $(call cmd,syscalls)
Did you mean to _replace_ rq-offsets-file rather than add
kmem_cache_size-file ?
(I also wonder if we want to just do slab or if we want to make this
mm-offsets.h and maybe put other things in it later, but I'm having
trouble thinking of other things we might want to generate)
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-10 5:33 ` [RFC PATCH 00/15] kmem_cache instances with static storage duration Linus Torvalds
@ 2026-01-10 6:16 ` Al Viro
2026-01-14 7:12 ` Harry Yoo
0 siblings, 1 reply; 52+ messages in thread
From: Al Viro @ 2026-01-10 6:16 UTC (permalink / raw)
To: Linus Torvalds
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
On Fri, Jan 09, 2026 at 07:33:41PM -1000, Linus Torvalds wrote:
> On Fri, 9 Jan 2026 at 18:01, Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > There's an alternative approach applicable at least to the caches
> > that are never destroyed, which covers a lot of them. No matter what,
> > runtime_const for pointers is not going to be faster than plain &,
> > so if we had struct kmem_cache instances with static storage duration, we
> > would be at least no worse off than we are with runtime_const variants.
>
> I like it. Much better than runtime_const for these things.
>
> That said, I don't love the commit messages. "turn xyzzy
> static-duration" reads very oddly to me, and because I saw the emails
> out of order originally it just made me go "whaa?"
>
> So can we please explain this some more obvious way. Maybe just "Make
> xyz be statically allocated". Yes, I'm nitpicking, but I feel like
> explaining core patches is worth the effort.
Point, but TBH the tail of the series is basically a demo for conversions
as well as "this is what I'd been testing, FSVO". In non-RFC form these
would be folded into fewer commits, if nothing else...
I'd really like to hear comments on the first two commits from SLAB
maintainers - for example, if slab_flags_t bits are considered a scarce
resource, the second commit would need to be modified. Still doable, but
representation would be more convoluted...
Another question is whether it's worth checking for accidental call
of e.g. kmem_cache_setup() on an already initialized cache, statically
or dynamically allocated. Again, up to maintainers - their subsystem,
their preferences.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-10 5:40 ` Matthew Wilcox
@ 2026-01-10 6:23 ` Al Viro
0 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-10 6:23 UTC (permalink / raw)
To: Matthew Wilcox
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Sat, Jan 10, 2026 at 05:40:34AM +0000, Matthew Wilcox wrote:
> On Sat, Jan 10, 2026 at 04:02:03AM +0000, Al Viro wrote:
> > +++ b/Kbuild
> > @@ -45,13 +45,24 @@ kernel/sched/rq-offsets.s: $(offsets-file)
> > $(rq-offsets-file): kernel/sched/rq-offsets.s FORCE
> > $(call filechk,offsets,__RQ_OFFSETS_H__)
> >
> > +# generate kmem_cache_size.h
> > +
> > +kmem_cache_size-file := include/generated/kmem_cache_size.h
> > +
> > +targets += mm/kmem_cache_size.s
> > +
> > +mm/kmem_cache_size.s: $(rq-offsets-file)
> > +
> > +$(kmem_cache_size-file): mm/kmem_cache_size.s FORCE
> > + $(call filechk,offsets,__KMEM_CACHE_SIZE_H__)
> > +
> > # Check for missing system calls
> >
> > quiet_cmd_syscalls = CALL $<
> > cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags) $(missing_syscalls_flags)
> >
> > PHONY += missing-syscalls
> > -missing-syscalls: scripts/checksyscalls.sh $(rq-offsets-file)
> > +missing-syscalls: scripts/checksyscalls.sh $(kmem_cache_size-file)
> > $(call cmd,syscalls)
>
> Did you mean to _replace_ rq-offsets-file rather than add
> kmem_cache_size-file ?
Insert kmem_cache_size-file into the chain, actually. At the moment, mainline has
$(bounds-file): kernel/bounds.s FORCE
$(call filechk,offsets,__LINUX_BOUNDS_H__)
$(timeconst-file): kernel/time/timeconst.bc FORCE
$(call filechk,gentimeconst)
arch/$(SRCARCH)/kernel/asm-offsets.s: $(timeconst-file) $(bounds-file)
$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE
$(call filechk,offsets,__ASM_OFFSETS_H__)
kernel/sched/rq-offsets.s: $(offsets-file)
$(rq-offsets-file): kernel/sched/rq-offsets.s FORCE
$(call filechk,offsets,__RQ_OFFSETS_H__)
missing-syscalls: scripts/checksyscalls.sh $(rq-offsets-file)
$(call cmd,syscalls)
with prepare having deps on $(offsets-file) and missing-syscalls, which
orders the entire sequence.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-10 6:16 ` Al Viro
@ 2026-01-14 7:12 ` Harry Yoo
0 siblings, 0 replies; 52+ messages in thread
From: Harry Yoo @ 2026-01-14 7:12 UTC (permalink / raw)
To: Al Viro
Cc: Linus Torvalds, linux-mm, Vlastimil Babka, linux-fsdevel,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
On Sat, Jan 10, 2026 at 06:16:00AM +0000, Al Viro wrote:
> On Fri, Jan 09, 2026 at 07:33:41PM -1000, Linus Torvalds wrote:
> > On Fri, 9 Jan 2026 at 18:01, Al Viro <viro@zeniv.linux.org.uk> wrote:
> > >
> > > There's an alternative approach applicable at least to the caches
> > > that are never destroyed, which covers a lot of them. No matter what,
> > > runtime_const for pointers is not going to be faster than plain &,
> > > so if we had struct kmem_cache instances with static storage duration, we
> > > would be at least no worse off than we are with runtime_const variants.
> >
> > I like it. Much better than runtime_const for these things.
> >
> > That said, I don't love the commit messages. "turn xyzzy
> > static-duration" reads very oddly to me, and because I saw the emails
> > out of order originally it just made me go "whaa?"
> >
> > So can we please explain this some more obvious way. Maybe just "Make
> > xyz be statically allocated". Yes, I'm nitpicking, but I feel like
> > explaining core patches is worth the effort.
>
> Point, but TBH the tail of the series is basically a demo for conversions
> as well as "this is what I'd been testing, FSVO". In non-RFC form these
> would be folded into fewer commits, if nothing else...
>
> I'd really like to hear comments on the first two commits from SLAB
> maintainers - for example, if slab_flags_t bits are considered a scarce
> resource, the second commit would need to be modified. Still doable, but
I think it's okay to introduce a new cache flag as long as it's simpler.
IMHO it's not a scarce resource (yet).
> representation would be more convoluted...
>
> Another question is whether it's worth checking for accidental call
> of e.g. kmem_cache_setup() on an already initialized cache, statically
> or dynamically allocated.
No strong opinion from me.
> Again, up to maintainers - their subsystem,
> their preferences.
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-10 4:02 ` [RFC PATCH 01/15] static kmem_cache instances for core caches Al Viro
2026-01-10 5:40 ` Matthew Wilcox
@ 2026-01-14 7:30 ` Harry Yoo
2026-01-14 7:38 ` Al Viro
2026-01-15 16:59 ` Vlastimil Babka
1 sibling, 2 replies; 52+ messages in thread
From: Harry Yoo @ 2026-01-14 7:30 UTC (permalink / raw)
To: Al Viro
Cc: linux-mm, Vlastimil Babka, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
On Sat, Jan 10, 2026 at 04:02:03AM +0000, Al Viro wrote:
> kmem_cache_create() and friends create new instances of
> struct kmem_cache and return pointers to those. Quite a few things in
> core kernel are allocated from such caches; each allocation involves
> dereferencing an assign-once pointer and for sufficiently hot ones that
> dereferencing does show in profiles.
>
> There had been patches floating around switching some of those
> to runtime_const infrastructure. Unfortunately, it's arch-specific
> and most of the architectures lack it.
>
> There's an alternative approach applicable at least to the caches
> that are never destroyed, which covers a lot of them. No matter what,
> runtime_const for pointers is not going to be faster than plain &,
> so if we had struct kmem_cache instances with static storage duration, we
> would be at least no worse off than we are with runtime_const variants.
>
> There are obstacles to doing that, but they turn out to be easy
> to deal with.
>
> 1) as it is, struct kmem_cache is opaque for anything outside of a few
> files in mm/*; that avoids serious headache with header dependencies,
> etc., and it's not something we want to lose. Solution: struct
> kmem_cache_opaque, with the size and alignment identical to struct
> kmem_cache. Calculation of size and alignment can be done via the same
> mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
> check for mismatches. With that done, we get an opaque type defined in
> linux/slab-static.h that can be used for declaring those caches.
> In linux/slab.h we add a forward declaration of kmem_cache_opaque +
> helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
> into pointer to kmem_cache.
>
> 2) real constructor of kmem_cache needs to be taught to deal with
> preallocated instances. That turns out to be easy - we already pass an
> obscene amount of optional arguments via struct kmem_cache_args, so we
> can stash the pointer to preallocated instance in there. Changes in
> mm/slab_common.c are very minor - we should treat preallocated caches
> as unmergable, use the instance passed to us instead of allocating a
> new one and we should not free them. That's it.
SLAB_NO_MERGE prevents both side of merging - when 1) creating the cache,
and when 2) another cache tries to create an alias from it.
Avoiding 1) makes sense, but is there a reason to prevent 2)?
If it's fine for other caches to merge into a cache with static
duration, then it's sufficient to update find_mergeable() to not attempt
creating an alias during cache creation if args->preallocated is
specified (instead of using SLAB_NO_MERGE).
--
Cheers,
Harry / Hyeonggon
> Note that slab-static.h is needed only in places that create
> such instances; all users need only slab.h (and they can be modular,
> unlike runtime_const-based approach).
>
> That covers the instances that never get destroyed. Quite a few
> fall into that category, but there's a major exception - anything in
> modules must be destroyed before the module gets removed. For example,
> filesystems that have their inodes allocated from a private kmem_cache
> can't make use of that technics for their inode allocations, etc.
>
> It's not that hard to deal with, but for now let's just ban
> including slab-static.h from modules.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-14 7:30 ` Harry Yoo
@ 2026-01-14 7:38 ` Al Viro
2026-01-15 16:59 ` Vlastimil Babka
1 sibling, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-14 7:38 UTC (permalink / raw)
To: Harry Yoo
Cc: linux-mm, Vlastimil Babka, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
On Wed, Jan 14, 2026 at 04:30:24PM +0900, Harry Yoo wrote:
> SLAB_NO_MERGE prevents both side of merging - when 1) creating the cache,
> and when 2) another cache tries to create an alias from it.
>
> Avoiding 1) makes sense, but is there a reason to prevent 2)?
>
> If it's fine for other caches to merge into a cache with static
> duration, then it's sufficient to update find_mergeable() to not attempt
> creating an alias during cache creation if args->preallocated is
> specified (instead of using SLAB_NO_MERGE).
Umm... For static-in-module - definitely (what if it goes away before
the dynamic alias?), for globally static... might be fine, I guess...
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
` (15 preceding siblings ...)
2026-01-10 5:33 ` [RFC PATCH 00/15] kmem_cache instances with static storage duration Linus Torvalds
@ 2026-01-15 0:46 ` Christoph Lameter (Ampere)
2026-01-15 2:08 ` Al Viro
16 siblings, 1 reply; 52+ messages in thread
From: Christoph Lameter (Ampere) @ 2026-01-15 0:46 UTC (permalink / raw)
To: Al Viro
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Sat, 10 Jan 2026, Al Viro wrote:
> 1) as it is, struct kmem_cache is opaque for anything outside of a few
> files in mm/*; that avoids serious headache with header dependencies,
> etc., and it's not something we want to lose. Solution: struct
> kmem_cache_opaque, with the size and alignment identical to struct
> kmem_cache. Calculation of size and alignment can be done via the same
> mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
> check for mismatches. With that done, we get an opaque type defined in
> linux/slab-static.h that can be used for declaring those caches.
> In linux/slab.h we add a forward declaration of kmem_cache_opaque +
> helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
> into pointer to kmem_cache.
Hmmm. A new kernel infrastructure feature: Opaque objects
Would that an deserve a separate abstraction so it is usable by other
subsystems?
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-15 0:46 ` Christoph Lameter (Ampere)
@ 2026-01-15 2:08 ` Al Viro
2026-01-15 19:10 ` Christoph Lameter (Ampere)
0 siblings, 1 reply; 52+ messages in thread
From: Al Viro @ 2026-01-15 2:08 UTC (permalink / raw)
To: Christoph Lameter (Ampere)
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Wed, Jan 14, 2026 at 04:46:04PM -0800, Christoph Lameter (Ampere) wrote:
> On Sat, 10 Jan 2026, Al Viro wrote:
>
> > 1) as it is, struct kmem_cache is opaque for anything outside of a few
> > files in mm/*; that avoids serious headache with header dependencies,
> > etc., and it's not something we want to lose. Solution: struct
> > kmem_cache_opaque, with the size and alignment identical to struct
> > kmem_cache. Calculation of size and alignment can be done via the same
> > mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
> > check for mismatches. With that done, we get an opaque type defined in
> > linux/slab-static.h that can be used for declaring those caches.
> > In linux/slab.h we add a forward declaration of kmem_cache_opaque +
> > helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
> > into pointer to kmem_cache.
>
> Hmmm. A new kernel infrastructure feature: Opaque objects
>
> Would that an deserve a separate abstraction so it is usable by other
> subsystems?
*shrug*
Probably could be done, but I don't see many applications for that.
Note that in this case objects are either of "never destroyed at all"
sort or "never destroyed until rmmod" one, and the latter already
requires a pretty careful handling.
If it's dynamically allocated, we have much more straightforward
mechanisms - see e.g. struct mount vs. struct vfsmount, where most
of the containing object is opaque for everyone outside of several
files in fs/*.c and the public part is embedded into it.
I'm not saying that no other similar cases exist, but until somebody
comes up with other examples...
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-14 7:30 ` Harry Yoo
2026-01-14 7:38 ` Al Viro
@ 2026-01-15 16:59 ` Vlastimil Babka
2026-06-11 17:13 ` Al Viro
1 sibling, 1 reply; 52+ messages in thread
From: Vlastimil Babka @ 2026-01-15 16:59 UTC (permalink / raw)
To: Harry Yoo, Al Viro, Mateusz Guzik
Cc: linux-mm, linux-fsdevel, Linus Torvalds, Christian Brauner,
Jan Kara, linux-kernel, Christoph Lameter (Ampere)
On 1/14/26 08:30, Harry Yoo wrote:
> On Sat, Jan 10, 2026 at 04:02:03AM +0000, Al Viro wrote:
>> kmem_cache_create() and friends create new instances of
>> struct kmem_cache and return pointers to those. Quite a few things in
>> core kernel are allocated from such caches; each allocation involves
>> dereferencing an assign-once pointer and for sufficiently hot ones that
>> dereferencing does show in profiles.
>>
>> There had been patches floating around switching some of those
>> to runtime_const infrastructure. Unfortunately, it's arch-specific
>> and most of the architectures lack it.
>>
>> There's an alternative approach applicable at least to the caches
>> that are never destroyed, which covers a lot of them. No matter what,
>> runtime_const for pointers is not going to be faster than plain &,
>> so if we had struct kmem_cache instances with static storage duration, we
>> would be at least no worse off than we are with runtime_const variants.
>>
>> There are obstacles to doing that, but they turn out to be easy
>> to deal with.
>>
>> 1) as it is, struct kmem_cache is opaque for anything outside of a few
>> files in mm/*; that avoids serious headache with header dependencies,
>> etc., and it's not something we want to lose. Solution: struct
>> kmem_cache_opaque, with the size and alignment identical to struct
>> kmem_cache. Calculation of size and alignment can be done via the same
>> mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
>> check for mismatches. With that done, we get an opaque type defined in
>> linux/slab-static.h that can be used for declaring those caches.
>> In linux/slab.h we add a forward declaration of kmem_cache_opaque +
>> helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
>> into pointer to kmem_cache.
>>
>> 2) real constructor of kmem_cache needs to be taught to deal with
>> preallocated instances. That turns out to be easy - we already pass an
>> obscene amount of optional arguments via struct kmem_cache_args, so we
>> can stash the pointer to preallocated instance in there. Changes in
>> mm/slab_common.c are very minor - we should treat preallocated caches
>> as unmergable, use the instance passed to us instead of allocating a
>> new one and we should not free them. That's it.
>
> SLAB_NO_MERGE prevents both side of merging - when 1) creating the cache,
> and when 2) another cache tries to create an alias from it.
>
> Avoiding 1) makes sense, but is there a reason to prevent 2)?
>
> If it's fine for other caches to merge into a cache with static
> duration, then it's sufficient to update find_mergeable() to not attempt
> creating an alias during cache creation if args->preallocated is
> specified (instead of using SLAB_NO_MERGE).
The merging prevention is my biggest concern with the approach. We could
potentially solve it by moving the sharing to a different layer than today's
sharing of kmem_cache objects with refcount, and instead have separate
instances that point to the same underlying storage (mainly the per-node and
per-cpu slabs/sheaves). It's possible it would also simplify the suboptimal
sysfs handling of today as the aliases could know their cache name and own
their symlinks.
However slabs and sheaves do have a parent kmem_cache pointer. It's how e.g.
kfree() works by virt_to_slab(obj) -> kmem_cache and then being like
kmem_cache_free().
So we could have kmem_cache->primary_cache field where the primary would
just point to self and aliasing caches to the primary, and newly created
slabs and sheaves would read that ->primary_cache to assign their kmem_cache
pointer. This is not a fasthpath operation so it shouldn't matter, and with
that there wouldn't be any mix of differing cache pointers so the aliases
could be destroyed easily. And then the primary cache wouldn't be able go
away as long as there are aliases, as it is today.
Only a dynamic cache or a non-module static cache thus could become a
primary, for module unload reasons.
For this to work fully mergeable in all scenarios of the order of creating
static vs dynamic aliases, there would however have to be a weird quirk for
static module caches - when such a cache is created, and there's no
compatible primary to become alias of, a dynamic, otherwise unused primary
would need to be created just to become the owner of the slabs and sheaves.
Because if a mergeable dynamic cache appears later, it would not be able to
become a primary for the static module cache to become alias of, because the
static module cache would already have existing slabs and sheaves pointing
to it.
And there might be other issues with this scheme I don't immediately see.
But maybe it's feasible.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-15 2:08 ` Al Viro
@ 2026-01-15 19:10 ` Christoph Lameter (Ampere)
2026-01-15 19:44 ` Al Viro
0 siblings, 1 reply; 52+ messages in thread
From: Christoph Lameter (Ampere) @ 2026-01-15 19:10 UTC (permalink / raw)
To: Al Viro
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Thu, 15 Jan 2026, Al Viro wrote:
> > Would that an deserve a separate abstraction so it is usable by other
> > subsystems?
>
> *shrug*
>
> Probably could be done, but I don't see many applications for that.
> Note that in this case objects are either of "never destroyed at all"
> sort or "never destroyed until rmmod" one, and the latter already
> requires a pretty careful handling.
>
> If it's dynamically allocated, we have much more straightforward
> mechanisms - see e.g. struct mount vs. struct vfsmount, where most
> of the containing object is opaque for everyone outside of several
> files in fs/*.c and the public part is embedded into it.
>
> I'm not saying that no other similar cases exist, but until somebody
> comes up with other examples...
Internal functions exist in the slab allocator that do what you want if
the opaqueness requirement is dropped. F.e. for the creation of kmalloc
caches we use do_kmem_cache_create():
void __init create_boot_cache(struct kmem_cache *s, const char *name,
unsigned int size, slab_flags_t flags,
unsigned int useroffset, unsigned int usersize)
{
int err;
unsigned int align = ARCH_KMALLOC_MINALIGN;
struct kmem_cache_args kmem_args = {};
/*
* kmalloc caches guarantee alignment of at least the largest
* power-of-two divisor of the size. For power-of-two sizes,
* it is the size itself.
*/
if (flags & SLAB_KMALLOC)
align = max(align, 1U << (ffs(size) - 1));
kmem_args.align = calculate_alignment(flags, align, size);
#ifdef CONFIG_HARDENED_USERCOPY
kmem_args.useroffset = useroffset;
kmem_args.usersize = usersize;
#endif
err = do_kmem_cache_create(s, name, size, &kmem_args, flags);
if (err)
panic("Creation of kmalloc slab %s size=%u failed. Reason %d\n",
name, size, err);
s->refcount = -1; /* Exempt from merging for now */
}
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 00/15] kmem_cache instances with static storage duration
2026-01-15 19:10 ` Christoph Lameter (Ampere)
@ 2026-01-15 19:44 ` Al Viro
0 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-01-15 19:44 UTC (permalink / raw)
To: Christoph Lameter (Ampere)
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Thu, Jan 15, 2026 at 11:10:00AM -0800, Christoph Lameter (Ampere) wrote:
> Internal functions exist in the slab allocator that do what you want if
> the opaqueness requirement is dropped. F.e. for the creation of kmalloc
> caches we use do_kmem_cache_create():
Yes, I know. Do you really want to expose e.g. slab_caches and slab_mutex
to the rest of the kernel? Surgery needed to have __kmem_cache_create()
do everything is not large - see the mm/slab_common.c parts in the first
two commits in this series.
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH 01/15] static kmem_cache instances for core caches
2026-01-15 16:59 ` Vlastimil Babka
@ 2026-06-11 17:13 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
0 siblings, 1 reply; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:13 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Harry Yoo, Mateusz Guzik, linux-mm, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, linux-kernel,
Christoph Lameter (Ampere)
On Thu, Jan 15, 2026 at 05:59:12PM +0100, Vlastimil Babka wrote:
[resurrecting an old thread]
> The merging prevention is my biggest concern with the approach.
How about allowing subsequent cache creation to pick an existing
static one as long as it's non-modular? That's easy enough to
do and it's minimally invasive.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH v2 0/9] kmem_cache instances with static storage duration
2026-06-11 17:13 ` Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 1/9] static kmem_cache instances for core caches Al Viro
` (9 more replies)
0 siblings, 10 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Changes since v1:
* milder restrictions on mergability (non-modular static cache
can be used as alias for later dynamic ones)
* consolidated conversions into fewer commits
* rebased to 7.1-rc6.
Branch lives in
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.kmem_cache_static
individual patches in followups.
Please, review.
kmem_cache_create() and friends create new instances of
struct kmem_cache and return pointers to those. Quite a few things in
core kernel are allocated from such caches; each allocation involves
dereferencing an assign-once pointer and for sufficiently hot ones that
dereferencing does show in profiles.
There had been patches floating around switching some of those
to runtime_const infrastructure. Unfortunately, it's arch-specific
and most of the architectures lack it.
There's an alternative approach applicable at least to the caches
that are never destroyed, which covers a lot of them. No matter what,
runtime_const for pointers is not going to be faster than plain &,
so if we had struct kmem_cache instances with static storage duration, we
would be at least no worse off than we are with runtime_const variants.
There are obstacles to doing that, but they turn out to be easy
to deal with.
1) as it is, struct kmem_cache is opaque for anything outside of a few
files in mm/*; that avoids serious headache with header dependencies,
etc., and it's not something we want to lose. Solution: struct
kmem_cache_opaque, with the size and alignment identical to struct
kmem_cache. Calculation of size and alignment can be done via the same
mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
check for mismatches. With that done, we get an opaque type defined in
linux/slab-static.h that can be used for declaring those caches.
In linux/slab.h we add a forward declaration of kmem_cache_opaque +
helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
into pointer to kmem_cache.
2) real constructor of kmem_cache needs to be taught to deal with
preallocated instances. That turns out to be easy - we already pass an
obscene amount of optional arguments via struct kmem_cache_args, so we
can stash the pointer to preallocated instance in there. Changes in
mm/slab_common.c are very minor - we should not merge preallocated caches
with anything already created, use the instance passed to us instead of
allocating a new one and we should not free them. That's it.
A set of helpers parallel to kmem_cache_create() and friends
(kmem_cache_setup(), etc.) is provided in the same linux/slab-static.h;
generally, conversion affects only a few lines.
Note that slab-static.h is needed only in places that create
such instances; all users need only slab.h (and they can be modular,
unlike runtime_const-based approach).
That covers the instances that never get destroyed. Quite a few
fall into that category, but there's a major exception - anything in
modules must be destroyed before the module gets removed. Note that
unlike runtime_constant-based approach, cache _uses_ in a module are
fine - if kmem_cache_opaque instance is exported, its address is available
to modules without any problems. It's caches _created_ in a module
that offer an extra twist.
Teaching kmem_cache_destroy() to skip actual freeing of given
kmem_cache instance is trivial; the problem is that kmem_cache_destroy()
may overlap with sysfs access to attributes of that cache. In that
case kmem_cache_destroy() may return before the instance gets freed -
freeing (from slab_kmem_cache_release()) happens when the refcount of
embedded kobject drops to zero. That's fine, since all references
to data structures in module's memory are already gone by the time
kmem_cache_destroy() returns. That, however, relies upon the struct
kmem_cache itself not being in module's memory; getting it unmapped
before slab_kmem_cache_release() has run needs to be avoided.
It's not hard to deal with, though. We need to make sure that
instance in a module will get to slab_kmem_cache_release() before the
module data gets freed. That's only a problem on sysfs setups -
otherwise it'll definitely be finished before kmem_cache_destroy()
returns.
Note that modules themselves have sysfs-exposed attributes,
so a similar problem already exists there. That's dealt with by
having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
reaching zero. Let's make use of that - have static-duration-in-module
kmem_cache instances grab a reference to that kobject upon setup and
drop it in the end of slab_kmem_cache_release().
Let setup helpers store the kobject to be pinned in
kmem_cache_args->owner (for preallocated; if somebody manually sets it
for non-preallocated case, it'll be ignored). That would be
&THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
If sysfs is enabled and we are dealing with preallocated instance,
let create_cache() grab and stash that reference in kmem_cache->owner
and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
instance.
Costs:
* a bit (SLAB_PREALLOCATED) is stolen from slab_flags_t
* such caches can't be merged with anything preexisting (obviously)
and subsequent cache creations can't merge with static-in-module
ones. If you want them more mergable, don't use that technics.
* you can't do kmem_cache_setup()/kmem_cache_destroy()/kmem_cache_setup()
on the same instance. Just don't do that.
Al Viro (9):
static kmem_cache instances for core caches
allow static-duration kmem_cache in modules
VFS caches: switch from runtime_const() machinery to slab-static.h
make inode_cache statically allocated
make mnt_cache statically allocated
make bh_cachep statically allocated
make seq_file_cache statically allocated
make thread component caches (fs_cachep, files_cachep, etc.)
statically allocated
make ufs_inode_cache statically allocated
Kbuild | 14 ++++++-
fs/buffer.c | 6 ++-
fs/dcache.c | 8 ++--
fs/file_table.c | 40 ++++++++----------
fs/inode.c | 6 ++-
fs/namei.c | 16 +++----
fs/namespace.c | 6 ++-
fs/seq_file.c | 6 ++-
fs/ufs/super.c | 9 ++--
include/asm-generic/vmlinux.lds.h | 6 +--
include/linux/fdtable.h | 3 +-
include/linux/fs_struct.h | 3 +-
include/linux/signal.h | 3 +-
include/linux/slab-static.h | 69 +++++++++++++++++++++++++++++++
include/linux/slab.h | 11 +++++
kernel/fork.c | 37 ++++++++++-------
mm/kmem_cache_size.c | 20 +++++++++
mm/slab.h | 1 +
mm/slab_common.c | 49 ++++++++++++++--------
mm/slub.c | 7 ++++
20 files changed, 231 insertions(+), 89 deletions(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
--
2.47.3
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH v2 1/9] static kmem_cache instances for core caches
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 2/9] allow static-duration kmem_cache in modules Al Viro
` (8 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
kmem_cache_create() and friends create new instances of
struct kmem_cache and return pointers to those. Quite a few things in
core kernel are allocated from such caches; each allocation involves
dereferencing an assign-once pointer and for sufficiently hot ones that
dereferencing does show in profiles.
There had been patches floating around switching some of those
to runtime_const infrastructure. Unfortunately, it's arch-specific
and most of the architectures lack it.
There's an alternative approach applicable at least to the caches
that are never destroyed, which covers a lot of them. No matter what,
runtime_const for pointers is not going to be faster than plain &,
so if we had struct kmem_cache instances with static storage duration, we
would be at least no worse off than we are with runtime_const variants.
There are obstacles to doing that, but they turn out to be easy
to deal with.
1) as it is, struct kmem_cache is opaque for anything outside of a few
files in mm/*; that avoids serious headache with header dependencies,
etc., and it's not something we want to lose. Solution: struct
kmem_cache_opaque, with the size and alignment identical to struct
kmem_cache. Calculation of size and alignment can be done via the same
mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
check for mismatches. With that done, we get an opaque type defined in
linux/slab-static.h that can be used for declaring those caches.
In linux/slab.h we add a forward declaration of kmem_cache_opaque +
helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
into pointer to kmem_cache.
2) real constructor of kmem_cache needs to be taught to deal with
preallocated instances. That turns out to be easy - we already pass an
obscene amount of optional arguments via struct kmem_cache_args, so we
can stash the pointer to preallocated instance in there. Changes in
mm/slab_common.c are very minor - we should not merge preallocated caches
with anything already created, use the instance passed to us instead of
allocating a new one and we should not free them. That's it.
Note that slab-static.h is needed only in places that create
such instances; all users need only slab.h (and they can be modular,
unlike runtime_const-based approach).
That covers the instances that never get destroyed. Quite a few
fall into that category, but there's a major exception - anything in
modules must be destroyed before the module gets removed. For example,
filesystems that have their inodes allocated from a private kmem_cache
can't make use of that technics for their inode allocations, etc.
It's not that hard to deal with, but for now let's just ban
including slab-static.h from modules.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Kbuild | 14 +++++++-
include/linux/slab-static.h | 65 +++++++++++++++++++++++++++++++++++++
include/linux/slab.h | 7 ++++
mm/kmem_cache_size.c | 20 ++++++++++++
mm/slab_common.c | 30 ++++++++---------
mm/slub.c | 7 ++++
6 files changed, 127 insertions(+), 16 deletions(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
diff --git a/Kbuild b/Kbuild
index a6a0192dea08..64f29f1f0e71 100644
--- a/Kbuild
+++ b/Kbuild
@@ -45,6 +45,17 @@ kernel/sched/rq-offsets.s: $(offsets-file)
$(rq-offsets-file): kernel/sched/rq-offsets.s FORCE
$(call filechk,offsets,__RQ_OFFSETS_H__)
+# generate kmem_cache_size.h
+
+kmem_cache_size-file := include/generated/kmem_cache_size.h
+
+targets += mm/kmem_cache_size.s
+
+mm/kmem_cache_size.s: $(rq-offsets-file)
+
+$(kmem_cache_size-file): mm/kmem_cache_size.s FORCE
+ $(call filechk,offsets,__KMEM_CACHE_SIZE_H__)
+
# Check for missing system calls
missing-syscalls-file := .tmp_missing-syscalls$(missing_syscalls_instance)
@@ -58,7 +69,8 @@ $(missing-syscalls-file): scripts/checksyscalls.sh $(rq-offsets-file) FORCE
$(call if_changed_dep,syscalls)
PHONY += missing-syscalls
-missing-syscalls: $(missing-syscalls-file)
+missing-syscalls: $(missing-syscalls-file) $(kmem_cache_size-file)
+ $(call cmd,syscalls)
# Check the manual modification of atomic headers
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
new file mode 100644
index 000000000000..47b2220b4988
--- /dev/null
+++ b/include/linux/slab-static.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SLAB_STATIC_H
+#define _LINUX_SLAB_STATIC_H
+
+#ifdef MODULE
+#error "can't use that in modules"
+#endif
+
+#include <generated/kmem_cache_size.h>
+
+/* same size and alignment as struct kmem_cache: */
+struct kmem_cache_opaque {
+ unsigned char opaque[KMEM_CACHE_SIZE];
+} __aligned(KMEM_CACHE_ALIGN);
+
+#define __KMEM_CACHE_SETUP(cache, name, size, flags, ...) \
+ __kmem_cache_create_args((name), (size), \
+ &(struct kmem_cache_args) { \
+ .preallocated = (cache), \
+ __VA_ARGS__}, (flags))
+
+static inline int
+kmem_cache_setup_usercopy(struct kmem_cache *s,
+ const char *name, unsigned int size,
+ unsigned int align, slab_flags_t flags,
+ unsigned int useroffset, unsigned int usersize,
+ void (*ctor)(void *))
+{
+ struct kmem_cache *res;
+ res = __KMEM_CACHE_SETUP(s, name, size, flags,
+ .align = align,
+ .ctor = ctor,
+ .useroffset = useroffset,
+ .usersize = usersize);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+ return 0;
+}
+
+static inline int
+kmem_cache_setup(struct kmem_cache *s,
+ const char *name, unsigned int size,
+ unsigned int align, slab_flags_t flags,
+ void (*ctor)(void *))
+{
+ struct kmem_cache *res;
+ res = __KMEM_CACHE_SETUP(s, name, size, flags,
+ .align = align,
+ .ctor = ctor);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+ return 0;
+}
+
+#define KMEM_CACHE_SETUP(s, __struct, __flags) \
+ __KMEM_CACHE_SETUP((s), #__struct, sizeof(struct __struct), (__flags), \
+ .align = __alignof__(struct __struct))
+
+#define KMEM_CACHE_SETUP_USERCOPY(s, __struct, __flags, __field) \
+ __KMEM_CACHE_SETUP((s), #__struct, sizeof(struct __struct), (__flags), \
+ .align = __alignof__(struct __struct), \
+ .useroffset = offsetof(struct __struct, __field), \
+ .usersize = sizeof_field(struct __struct, __field))
+
+#endif
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2b5ab488e96b..f63657d3cf81 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -265,11 +265,17 @@ enum _slab_flag_bits {
struct list_lru;
struct mem_cgroup;
+struct kmem_cache_opaque;
/*
* struct kmem_cache related prototypes
*/
bool slab_is_available(void);
+static inline struct kmem_cache *to_kmem_cache(struct kmem_cache_opaque *p)
+{
+ return (struct kmem_cache *)p;
+}
+
/**
* struct kmem_cache_args - Less common arguments for kmem_cache_create()
*
@@ -372,6 +378,7 @@ struct kmem_cache_args {
* %0 means no sheaves will be created.
*/
unsigned int sheaf_capacity;
+ struct kmem_cache *preallocated;
};
struct kmem_cache *__kmem_cache_create_args(const char *name,
diff --git a/mm/kmem_cache_size.c b/mm/kmem_cache_size.c
new file mode 100644
index 000000000000..1ddbfa41a507
--- /dev/null
+++ b/mm/kmem_cache_size.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generate definitions needed by the preprocessor.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#define COMPILE_OFFSETS
+#include <linux/kbuild.h>
+#include "slab.h"
+
+int main(void)
+{
+ /* The constants to put into include/generated/kmem_cache_size.h */
+ DEFINE(KMEM_CACHE_SIZE, sizeof(struct kmem_cache));
+ DEFINE(KMEM_CACHE_ALIGN, __alignof(struct kmem_cache));
+ /* End of constants */
+
+ return 0;
+}
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 8b661fff5eed..57de41c7f1aa 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -182,6 +182,9 @@ bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags)
if (args->ctor)
return true;
+ if (args->preallocated)
+ return true;
+
if (IS_ENABLED(CONFIG_HARDENED_USERCOPY) && args->usersize)
return true;
@@ -234,33 +237,30 @@ static struct kmem_cache *create_cache(const char *name,
struct kmem_cache_args *args,
slab_flags_t flags)
{
- struct kmem_cache *s;
+ struct kmem_cache *s = args->preallocated;
int err;
/* If a custom freelist pointer is requested make sure it's sane. */
- err = -EINVAL;
if (args->use_freeptr_offset &&
(args->freeptr_offset >= object_size ||
(!(flags & SLAB_TYPESAFE_BY_RCU) && !args->ctor) ||
!IS_ALIGNED(args->freeptr_offset, __alignof__(freeptr_t))))
- goto out;
+ return ERR_PTR(-EINVAL);
- err = -ENOMEM;
- s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
- if (!s)
- goto out;
+ if (!s) {
+ s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
+ if (!s)
+ return ERR_PTR(-ENOMEM);
+ }
err = do_kmem_cache_create(s, name, object_size, args, flags);
- if (err)
- goto out_free_cache;
-
+ if (unlikely(err)) {
+ if (!args->preallocated)
+ kmem_cache_free(kmem_cache, s);
+ return ERR_PTR(err);
+ }
s->refcount = 1;
list_add(&s->list, &slab_caches);
return s;
-
-out_free_cache:
- kmem_cache_free(kmem_cache, s);
-out:
- return ERR_PTR(err);
}
static struct kmem_cache *
diff --git a/mm/slub.c b/mm/slub.c
index a2bf3756ca7d..c0765173911d 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -50,6 +50,7 @@
#include <linux/irq_work.h>
#include <linux/kprobes.h>
#include <linux/debugfs.h>
+#include <linux/slab-static.h>
#include <trace/events/kmem.h>
#include "internal.h"
@@ -8484,6 +8485,12 @@ void __init kmem_cache_init(void)
boot_kmem_cache_node;
int node;
+ /* verify that kmem_cache_opaque is correct */
+ BUILD_BUG_ON(sizeof(struct kmem_cache) !=
+ sizeof(struct kmem_cache_opaque));
+ BUILD_BUG_ON(__alignof(struct kmem_cache) !=
+ __alignof(struct kmem_cache_opaque));
+
if (debug_guardpage_minorder())
slub_max_order = 0;
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 2/9] allow static-duration kmem_cache in modules
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
2026-06-11 17:14 ` [PATCH v2 1/9] static kmem_cache instances for core caches Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 3/9] VFS caches: switch from runtime_const() machinery to slab-static.h Al Viro
` (7 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
We need to make sure that instance in a module will get to
slab_kmem_cache_release() before the module data gets freed. That's only
a problem on sysfs setups - otherwise it'll definitely be finished before
kmem_cache_destroy() returns.
Note that modules themselves have sysfs-exposed attributes,
so a similar problem already exists there. That's dealt with by
having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
reaching zero. Let's make use of that - have static-duration-in-module
kmem_cache instances grab a reference to that kobject upon setup and
drop it in the end of slab_kmem_cache_release().
Let setup helpers store the kobjetct to be pinned in
kmem_cache_args->owner (for preallocated; if somebody manually sets it
for non-preallocated case, it'll be ignored). That would be
&THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
If sysfs is enabled and we are dealing with preallocated instance,
let create_cache() grab and stash that reference in kmem_cache->owner
and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
instance.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/slab-static.h | 12 ++++++++----
include/linux/slab.h | 4 ++++
mm/slab.h | 1 +
mm/slab_common.c | 25 ++++++++++++++++++++-----
4 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
index 47b2220b4988..16d1564b4a4b 100644
--- a/include/linux/slab-static.h
+++ b/include/linux/slab-static.h
@@ -2,10 +2,7 @@
#ifndef _LINUX_SLAB_STATIC_H
#define _LINUX_SLAB_STATIC_H
-#ifdef MODULE
-#error "can't use that in modules"
-#endif
-
+#include <linux/init.h>
#include <generated/kmem_cache_size.h>
/* same size and alignment as struct kmem_cache: */
@@ -13,9 +10,16 @@ struct kmem_cache_opaque {
unsigned char opaque[KMEM_CACHE_SIZE];
} __aligned(KMEM_CACHE_ALIGN);
+#ifdef MODULE
+#define THIS_MODULE_KOBJ &THIS_MODULE->mkobj.kobj
+#else
+#define THIS_MODULE_KOBJ NULL
+#endif
+
#define __KMEM_CACHE_SETUP(cache, name, size, flags, ...) \
__kmem_cache_create_args((name), (size), \
&(struct kmem_cache_args) { \
+ .owner = THIS_MODULE_KOBJ, \
.preallocated = (cache), \
__VA_ARGS__}, (flags))
diff --git a/include/linux/slab.h b/include/linux/slab.h
index f63657d3cf81..c95ad771ece2 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -62,6 +62,7 @@ enum _slab_flag_bits {
#if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
_SLAB_OBJ_EXT_IN_OBJ,
#endif
+ _SLAB_PREALLOCATED,
_SLAB_FLAGS_LAST_BIT
};
@@ -248,6 +249,8 @@ enum _slab_flag_bits {
#define SLAB_OBJ_EXT_IN_OBJ __SLAB_FLAG_UNUSED
#endif
+#define SLAB_PREALLOCATED __SLAB_FLAG_BIT(_SLAB_PREALLOCATED)
+
/*
* ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
*
@@ -379,6 +382,7 @@ struct kmem_cache_args {
*/
unsigned int sheaf_capacity;
struct kmem_cache *preallocated;
+ struct kobject *owner;
};
struct kmem_cache *__kmem_cache_create_args(const char *name,
diff --git a/mm/slab.h b/mm/slab.h
index bf2f87acf5e3..8b1db0d03226 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -219,6 +219,7 @@ struct kmem_cache {
struct list_head list; /* List of slab caches */
#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
+ struct kobject *owner; /* keep that pinned while alive */
#endif
#ifdef CONFIG_SLAB_FREELIST_HARDENED
unsigned long random;
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 57de41c7f1aa..2567c1c19847 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -182,13 +182,10 @@ bool slab_args_unmergeable(struct kmem_cache_args *args, slab_flags_t flags)
if (args->ctor)
return true;
- if (args->preallocated)
- return true;
-
if (IS_ENABLED(CONFIG_HARDENED_USERCOPY) && args->usersize)
return true;
- if (flags & SLAB_NEVER_MERGE)
+ if (flags & (SLAB_PREALLOCATED | SLAB_NEVER_MERGE))
return true;
return false;
@@ -258,6 +255,12 @@ static struct kmem_cache *create_cache(const char *name,
kmem_cache_free(kmem_cache, s);
return ERR_PTR(err);
}
+#ifdef CONFIG_SYSFS
+ if (flags & SLAB_PREALLOCATED) {
+ s->owner = args->owner;
+ kobject_get(s->owner);
+ }
+#endif
s->refcount = 1;
list_add(&s->list, &slab_caches);
return s;
@@ -366,6 +369,12 @@ struct kmem_cache *__kmem_cache_create_args(const char *name,
object_size - args->usersize < args->useroffset))
args->usersize = args->useroffset = 0;
+ if (args->preallocated) {
+ flags |= SLAB_PREALLOCATED;
+ if (args->owner)
+ flags |= SLAB_NO_MERGE;
+ }
+
s = __kmem_cache_alias(name, object_size, flags, args);
if (s)
goto out_unlock;
@@ -521,7 +530,13 @@ void slab_kmem_cache_release(struct kmem_cache *s)
{
__kmem_cache_release(s);
kfree_const(s->name);
- kmem_cache_free(kmem_cache, s);
+ if (!(s->flags & SLAB_PREALLOCATED)) {
+ kmem_cache_free(kmem_cache, s);
+ return;
+ }
+#ifdef CONFIG_SYSFS
+ kobject_put(s->owner);
+#endif
}
void kmem_cache_destroy(struct kmem_cache *s)
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 3/9] VFS caches: switch from runtime_const() machinery to slab-static.h
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
2026-06-11 17:14 ` [PATCH v2 1/9] static kmem_cache instances for core caches Al Viro
2026-06-11 17:14 ` [PATCH v2 2/9] allow static-duration kmem_cache in modules Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 4/9] make inode_cache statically allocated Al Viro
` (6 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Four VFS caches are currently playing games with runtime_const() to
reduce the overhead of pointer traversals - dentry, file, backing_file
and filename. All of these kmem_cache instances can be allocated
statically now, getting rid of runtime_const() games.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 8 +++----
fs/file_table.c | 40 ++++++++++++++-----------------
fs/namei.c | 16 ++++++-------
include/asm-generic/vmlinux.lds.h | 6 +----
4 files changed, 31 insertions(+), 39 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 2c61aeea41f4..e2feea82682a 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -32,6 +32,7 @@
#include <linux/bit_spinlock.h>
#include <linux/rculist_bl.h>
#include <linux/list_lru.h>
+#include <linux/slab-static.h>
#include "internal.h"
#include "mount.h"
@@ -86,8 +87,8 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
EXPORT_SYMBOL(rename_lock);
-static struct kmem_cache *__dentry_cache __ro_after_init;
-#define dentry_cache runtime_const_ptr(__dentry_cache)
+static struct kmem_cache_opaque __dentry_cache;
+#define dentry_cache to_kmem_cache(&__dentry_cache)
const struct qstr empty_name = QSTR_INIT("", 0);
EXPORT_SYMBOL(empty_name);
@@ -3362,10 +3363,9 @@ static void __init dcache_init(void)
* but it is probably not worth it because of the cache nature
* of the dcache.
*/
- __dentry_cache = KMEM_CACHE_USERCOPY(dentry,
+ KMEM_CACHE_SETUP_USERCOPY(dentry_cache, dentry,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_ACCOUNT,
d_shortname.string);
- runtime_const_init(ptr, __dentry_cache);
/* Hash may have been set up in dcache_init_early */
if (!hashdist)
diff --git a/fs/file_table.c b/fs/file_table.c
index 16e52e7fc2ac..3844bc9f0e0a 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -27,11 +27,10 @@
#include <linux/task_work.h>
#include <linux/swap.h>
#include <linux/kmemleak.h>
+#include <linux/slab-static.h>
#include <linux/atomic.h>
-#include <asm/runtime-const.h>
-
#include "internal.h"
/* sysctl tunables... */
@@ -40,10 +39,10 @@ static struct files_stat_struct files_stat = {
};
/* SLAB cache for file structures */
-static struct kmem_cache *__filp_cache __ro_after_init;
-#define filp_cache runtime_const_ptr(__filp_cache)
-static struct kmem_cache *__bfilp_cache __ro_after_init;
-#define bfilp_cache runtime_const_ptr(__bfilp_cache)
+static struct kmem_cache_opaque file_cache;
+static struct kmem_cache_opaque backing_file_cache;
+#define filp_cache to_kmem_cache(&file_cache)
+#define bfilp_cache to_kmem_cache(&backing_file_cache)
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
@@ -629,22 +628,19 @@ void fput_close(struct file *file)
void __init files_init(void)
{
- struct kmem_cache_args args = {
- .use_freeptr_offset = true,
- .freeptr_offset = offsetof(struct file, f_freeptr),
- };
-
- __filp_cache = kmem_cache_create("filp", sizeof(struct file), &args,
- SLAB_HWCACHE_ALIGN | SLAB_PANIC |
- SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU);
- runtime_const_init(ptr, __filp_cache);
-
- args.freeptr_offset = offsetof(struct backing_file, bf_freeptr);
- __bfilp_cache = kmem_cache_create("bfilp", sizeof(struct backing_file),
- &args, SLAB_HWCACHE_ALIGN | SLAB_PANIC |
- SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU);
- runtime_const_init(ptr, __bfilp_cache);
-
+ __KMEM_CACHE_SETUP(filp_cache, "filp", sizeof(struct file),
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+ SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
+ .use_freeptr_offset = true,
+ .freeptr_offset = offsetof(struct file,
+ f_freeptr));
+
+ __KMEM_CACHE_SETUP(bfilp_cache, "bfilp", sizeof(struct backing_file),
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+ SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
+ .use_freeptr_offset = true,
+ .freeptr_offset = offsetof(struct backing_file,
+ bf_freeptr));
percpu_counter_init(&nr_files, 0, GFP_KERNEL);
}
diff --git a/fs/namei.c b/fs/namei.c
index c7fac83c9a85..7dd7edfa3a02 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -40,8 +40,7 @@
#include <linux/bitops.h>
#include <linux/init_task.h>
#include <linux/uaccess.h>
-
-#include <asm/runtime-const.h>
+#include <linux/slab-static.h>
#include "internal.h"
#include "mount.h"
@@ -126,15 +125,16 @@
*/
/* SLAB cache for struct filename instances */
-static struct kmem_cache *__names_cache __ro_after_init;
-#define names_cache runtime_const_ptr(__names_cache)
+static struct kmem_cache_opaque __names_cache;
+#define names_cache to_kmem_cache(&__names_cache)
void __init filename_init(void)
{
- __names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
- EMBEDDED_NAME_MAX, NULL);
- runtime_const_init(ptr, __names_cache);
+ kmem_cache_setup_usercopy(names_cache, "names_cache",
+ sizeof(struct filename), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ offsetof(struct filename, iname),
+ EMBEDDED_NAME_MAX, NULL);
}
static inline struct filename *alloc_filename(void)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 60c8c22fd3e4..4719269086c7 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -966,11 +966,7 @@
#define RUNTIME_CONST_VARIABLES \
RUNTIME_CONST(shift, d_hash_shift) \
- RUNTIME_CONST(ptr, dentry_hashtable) \
- RUNTIME_CONST(ptr, __dentry_cache) \
- RUNTIME_CONST(ptr, __names_cache) \
- RUNTIME_CONST(ptr, __filp_cache) \
- RUNTIME_CONST(ptr, __bfilp_cache)
+ RUNTIME_CONST(ptr, dentry_hashtable)
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
#define KUNIT_TABLE() \
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 4/9] make inode_cache statically allocated
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (2 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 3/9] VFS caches: switch from runtime_const() machinery to slab-static.h Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 5/9] make mnt_cache " Al Viro
` (5 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/inode.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 62c579a0cf7d..1c657ac99084 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -23,6 +23,7 @@
#include <linux/rw_hint.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/slab-static.h>
#include <trace/events/writeback.h>
#define CREATE_TRACE_POINTS
#include <trace/events/timestamp.h>
@@ -76,7 +77,8 @@ EXPORT_SYMBOL(empty_aops);
static DEFINE_PER_CPU(unsigned long, nr_inodes);
static DEFINE_PER_CPU(unsigned long, nr_unused);
-static struct kmem_cache *inode_cachep __ro_after_init;
+static struct kmem_cache_opaque inode_cache;
+#define inode_cachep to_kmem_cache(&inode_cache)
static long get_nr_inodes(void)
{
@@ -2598,7 +2600,7 @@ void __init inode_init_early(void)
void __init inode_init(void)
{
/* inode slab cache */
- inode_cachep = kmem_cache_create("inode_cache",
+ kmem_cache_setup(inode_cachep, "inode_cache",
sizeof(struct inode),
0,
(SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 5/9] make mnt_cache statically allocated
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (3 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 4/9] make inode_cache statically allocated Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 6/9] make bh_cachep " Al Viro
` (4 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index fe919abd2f01..e03c3e7e0a36 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -34,6 +34,7 @@
#include <linux/mnt_idmapping.h>
#include <linux/pidfs.h>
#include <linux/nstree.h>
+#include <linux/slab-static.h>
#include "pnode.h"
#include "internal.h"
@@ -79,7 +80,8 @@ static u64 mnt_id_ctr = MNT_UNIQUE_ID_OFFSET;
static struct hlist_head *mount_hashtable __ro_after_init;
static struct hlist_head *mountpoint_hashtable __ro_after_init;
-static struct kmem_cache *mnt_cache __ro_after_init;
+static struct kmem_cache_opaque __mnt_cache;
+#define mnt_cache to_kmem_cache(&__mnt_cache)
static DECLARE_RWSEM(namespace_sem);
static HLIST_HEAD(unmounted); /* protected by namespace_sem */
static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
@@ -6234,7 +6236,7 @@ void __init mnt_init(void)
{
int err;
- mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
+ kmem_cache_setup(mnt_cache, "mnt_cache", sizeof(struct mount),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
mount_hashtable = alloc_large_system_hash("Mount-cache",
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 6/9] make bh_cachep statically allocated
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (4 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 5/9] make mnt_cache " Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 7/9] make seq_file_cache " Al Viro
` (3 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/buffer.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index b0b3792b1496..e834f7091f51 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -51,6 +51,7 @@
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/sched/isolation.h>
+#include <linux/slab-static.h>
#include "internal.h"
@@ -2906,7 +2907,8 @@ EXPORT_SYMBOL(try_to_free_buffers);
/*
* Buffer-head allocation
*/
-static struct kmem_cache *bh_cachep __ro_after_init;
+static struct kmem_cache_opaque bh_cache;
+#define bh_cachep to_kmem_cache(&bh_cache)
/*
* Once the number of bh's in the machine exceeds this level, we start
@@ -3065,7 +3067,7 @@ void __init buffer_init(void)
unsigned long nrpages;
int ret;
- bh_cachep = KMEM_CACHE(buffer_head,
+ KMEM_CACHE_SETUP(bh_cachep, buffer_head,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC);
/*
* Limit the bh occupancy to 10% of ZONE_NORMAL
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 7/9] make seq_file_cache statically allocated
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (5 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 6/9] make bh_cachep " Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 8/9] make thread component caches (fs_cachep, files_cachep, etc.) " Al Viro
` (2 subsequent siblings)
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/seq_file.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 4745db2a34d1..7cb40ae83f9b 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -20,11 +20,13 @@
#include <linux/printk.h>
#include <linux/string_helpers.h>
#include <linux/uio.h>
+#include <linux/slab-static.h>
#include <linux/uaccess.h>
#include <asm/page.h>
-static struct kmem_cache *seq_file_cache __ro_after_init;
+static struct kmem_cache_opaque __seq_file_cache;
+#define seq_file_cache to_kmem_cache(&__seq_file_cache)
static void seq_set_overflow(struct seq_file *m)
{
@@ -1140,5 +1142,5 @@ EXPORT_SYMBOL(seq_hlist_next_percpu);
void __init seq_file_init(void)
{
- seq_file_cache = KMEM_CACHE(seq_file, SLAB_ACCOUNT|SLAB_PANIC);
+ KMEM_CACHE_SETUP(seq_file_cache, seq_file, SLAB_ACCOUNT|SLAB_PANIC);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 8/9] make thread component caches (fs_cachep, files_cachep, etc.) statically allocated
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (6 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 7/9] make seq_file_cache " Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 9/9] make ufs_inode_cache " Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
All of them are created in kernel/fork.c, might as well convert all
at once...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/fdtable.h | 3 ++-
include/linux/fs_struct.h | 3 ++-
include/linux/signal.h | 3 ++-
kernel/fork.c | 37 +++++++++++++++++++++----------------
4 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index c45306a9f007..f2d553f99c58 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -113,6 +113,7 @@ int iterate_fd(struct files_struct *, unsigned,
extern int close_fd(unsigned int fd);
extern struct file *file_close_fd(unsigned int fd);
-extern struct kmem_cache *files_cachep;
+extern struct kmem_cache_opaque files_cache;
+#define files_cachep to_kmem_cache(&files_cache)
#endif /* __LINUX_FDTABLE_H */
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 0070764b790a..e8c9fac5b7b7 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -15,7 +15,8 @@ struct fs_struct {
struct path root, pwd;
} __randomize_layout;
-extern struct kmem_cache *fs_cachep;
+extern struct kmem_cache_opaque fs_struct_cache;
+#define fs_cachep to_kmem_cache(&fs_struct_cache)
extern void exit_fs(struct task_struct *);
extern void set_fs_root(struct fs_struct *, const struct path *);
diff --git a/include/linux/signal.h b/include/linux/signal.h
index f19816832f05..a0c7fee8b22a 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -323,7 +323,8 @@ static inline void disallow_signal(int sig)
kernel_sigaction(sig, SIG_IGN);
}
-extern struct kmem_cache *sighand_cachep;
+extern struct kmem_cache_opaque sighand_cache;
+#define sighand_cachep to_kmem_cache(&sighand_cache)
extern bool unhandled_signal(struct task_struct *tsk, int sig);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8ac38beae360..618f19bb482a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -111,6 +111,7 @@
#include <linux/unwind_deferred.h>
#include <linux/pgalloc.h>
#include <linux/uaccess.h>
+#include <linux/slab-static.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -180,7 +181,8 @@ void __weak arch_release_task_struct(struct task_struct *tsk)
{
}
-static struct kmem_cache *task_struct_cachep;
+static struct kmem_cache_opaque task_struct_cache;
+#define task_struct_cachep to_kmem_cache(&task_struct_cache)
static inline struct task_struct *alloc_task_struct_node(int node)
{
@@ -425,7 +427,8 @@ static void free_thread_stack(struct task_struct *tsk)
#else /* !(THREAD_SIZE >= PAGE_SIZE) */
-static struct kmem_cache *thread_stack_cache;
+static struct kmem_cache_opaque __thread_stack_cache;
+#define thread_stack_cache to_kmem_cache(&__thread_stack_cache)
static void thread_stack_free_rcu(struct rcu_head *rh)
{
@@ -456,29 +459,31 @@ static void free_thread_stack(struct task_struct *tsk)
void thread_stack_cache_init(void)
{
- thread_stack_cache = kmem_cache_create_usercopy("thread_stack",
- THREAD_SIZE, THREAD_SIZE, 0, 0,
+ kmem_cache_setup_usercopy(thread_stack_cache, "thread_stack",
+ THREAD_SIZE, THREAD_SIZE,
+ SLAB_PANIC, 0,
THREAD_SIZE, NULL);
- BUG_ON(thread_stack_cache == NULL);
}
#endif /* THREAD_SIZE >= PAGE_SIZE */
#endif /* CONFIG_VMAP_STACK */
/* SLAB cache for signal_struct structures (tsk->signal) */
-static struct kmem_cache *signal_cachep;
+static struct kmem_cache_opaque signal_cache;
+#define signal_cachep to_kmem_cache(&signal_cache)
/* SLAB cache for sighand_struct structures (tsk->sighand) */
-struct kmem_cache *sighand_cachep;
+struct kmem_cache_opaque sighand_cache;
/* SLAB cache for files_struct structures (tsk->files) */
-struct kmem_cache *files_cachep;
+struct kmem_cache_opaque files_cache;
/* SLAB cache for fs_struct structures (tsk->fs) */
-struct kmem_cache *fs_cachep;
+struct kmem_cache_opaque fs_struct_cache;
/* SLAB cache for mm_struct structures (tsk->mm) */
-static struct kmem_cache *mm_cachep;
+static struct kmem_cache_opaque mm_cache;
+#define mm_cachep to_kmem_cache(&mm_cache)
static void account_kernel_stack(struct task_struct *tsk, int account)
{
@@ -859,7 +864,7 @@ void __init fork_init(void)
/* create a slab on which task_structs can be allocated */
task_struct_whitelist(&useroffset, &usersize);
- task_struct_cachep = kmem_cache_create_usercopy("task_struct",
+ kmem_cache_setup_usercopy(task_struct_cachep, "task_struct",
arch_task_struct_size, align,
SLAB_PANIC|SLAB_ACCOUNT,
useroffset, usersize, NULL);
@@ -3079,7 +3084,7 @@ void __init mm_cache_init(void)
*/
mm_size = sizeof(struct mm_struct) + cpumask_size() + mm_cid_size();
- mm_cachep = kmem_cache_create_usercopy("mm_struct",
+ kmem_cache_setup_usercopy(mm_cachep, "mm_struct",
mm_size, ARCH_MIN_MMSTRUCT_ALIGN,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
offsetof(struct mm_struct, saved_auxv),
@@ -3089,19 +3094,19 @@ void __init mm_cache_init(void)
void __init proc_caches_init(void)
{
- sighand_cachep = kmem_cache_create("sighand_cache",
+ kmem_cache_setup(sighand_cachep, "sighand_cache",
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU|
SLAB_ACCOUNT, sighand_ctor);
- signal_cachep = kmem_cache_create("signal_cache",
+ kmem_cache_setup(signal_cachep, "signal_cache",
sizeof(struct signal_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
- files_cachep = kmem_cache_create("files_cache",
+ kmem_cache_setup(files_cachep, "files_cache",
sizeof(struct files_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
- fs_cachep = kmem_cache_create("fs_cache",
+ kmem_cache_setup(fs_cachep, "fs_cache",
sizeof(struct fs_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v2 9/9] make ufs_inode_cache statically allocated
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (7 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 8/9] make thread component caches (fs_cachep, files_cachep, etc.) " Al Viro
@ 2026-06-11 17:14 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
9 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-11 17:14 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
A modular example I used for testing...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/super.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index c4831a8b9b3f..72053bc9c8dc 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -90,6 +90,7 @@
#include <linux/log2.h>
#include <linux/seq_file.h>
#include <linux/iversion.h>
+#include <linux/slab-static.h>
#include "ufs_fs.h"
#include "ufs.h"
@@ -1353,7 +1354,8 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static struct kmem_cache * ufs_inode_cachep;
+static struct kmem_cache_opaque ufs_inode_cache;
+#define ufs_inode_cachep to_kmem_cache(&ufs_inode_cache)
static struct inode *ufs_alloc_inode(struct super_block *sb)
{
@@ -1383,16 +1385,13 @@ static void init_once(void *foo)
static int __init init_inodecache(void)
{
- ufs_inode_cachep = kmem_cache_create_usercopy("ufs_inode_cache",
+ return kmem_cache_setup_usercopy(ufs_inode_cachep, "ufs_inode_cache",
sizeof(struct ufs_inode_info), 0,
(SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT),
offsetof(struct ufs_inode_info, i_u1.i_symlink),
sizeof_field(struct ufs_inode_info,
i_u1.i_symlink),
init_once);
- if (ufs_inode_cachep == NULL)
- return -ENOMEM;
- return 0;
}
static void destroy_inodecache(void)
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 00/10] kmem_cache instances with static storage duration
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
` (8 preceding siblings ...)
2026-06-11 17:14 ` [PATCH v2 9/9] make ufs_inode_cache " Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 01/10] static kmem_cache instances for core caches: infrastructure Al Viro
` (10 more replies)
9 siblings, 11 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Changes since v2:
* fixed the braindamage in /sys/kernel/slab (any statically allocated
caches should just use their name for subdirectory, whether they are mergable
or not)
* infrastructure bits slightly reordered and carved in hopefully saner
way.
* rebased to 7.1-rc7.
Changes since v1:
* milder restrictions on mergability (non-modular static cache
can be used as alias for later dynamic ones)
* consolidated conversions into fewer commits
* rebased to 7.1-rc6.
Branch lives in
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.kmem_cache_static
individual patches in followups.
Please, review. It appears to work; the impact on merging is very small -
on the testbox here (251 distinct aliases) mainline gets 140 kmem_cache
instances and this series gets 142 - fs_cachep and names_cache get split
from the group of 192-byte caches. Considering the contents and use patterns
for those two... we might be better off that way, actually.
kmem_cache_create() and friends create new instances of
struct kmem_cache and return pointers to those. Quite a few things in
core kernel are allocated from such caches; each allocation involves
dereferencing an assign-once pointer and for sufficiently hot ones that
dereferencing does show in profiles.
There had been patches floating around switching some of those
to runtime_const infrastructure. Unfortunately, it's arch-specific
and most of the architectures lack it.
There's an alternative approach applicable at least to the caches
that are never destroyed, which covers a lot of them. No matter what,
runtime_const for pointers is not going to be faster than plain &,
so if we had struct kmem_cache instances with static storage duration, we
would be at least no worse off than we are with runtime_const variants.
There are obstacles to doing that, but they turn out to be easy
to deal with.
1) as it is, struct kmem_cache is opaque for anything outside of a few
files in mm/*; that avoids serious headache with header dependencies,
etc., and it's not something we want to lose. Solution: struct
kmem_cache_opaque, with the size and alignment identical to struct
kmem_cache. Calculation of size and alignment can be done via the same
mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
check for mismatches. With that done, we get an opaque type defined in
linux/slab-static.h that can be used for declaring those caches.
In linux/slab.h we add a forward declaration of kmem_cache_opaque +
helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
into pointer to kmem_cache.
2) real constructor of kmem_cache needs to be taught to deal with
preallocated instances. That turns out to be easy - we already pass an
obscene amount of optional arguments via struct kmem_cache_args, so we
can stash the pointer to preallocated instance in there. Changes in
mm/slab_common.c are very minor - we should not merge preallocated caches
with anything already created, use the instance passed to us instead of
allocating a new one and we should not free them. That's it.
A set of helpers parallel to kmem_cache_create() and friends
(kmem_cache_setup(), etc.) is provided in the same linux/slab-static.h;
generally, conversion affects only a few lines.
Note that slab-static.h is needed only in places that create
such instances; all users need only slab.h (and they can be modular,
unlike runtime_const-based approach).
That covers the instances that never get destroyed. Quite a few
fall into that category, but there's a major exception - anything in
modules must be destroyed before the module gets removed. Note that
unlike runtime_constant-based approach, cache _uses_ in a module are
fine - if kmem_cache_opaque instance is exported, its address is available
to modules without any problems. It's caches _created_ in a module
that offer an extra twist.
Teaching kmem_cache_destroy() to skip actual freeing of given
kmem_cache instance is trivial; the problem is that kmem_cache_destroy()
may overlap with sysfs access to attributes of that cache. In that
case kmem_cache_destroy() may return before the instance gets freed -
freeing (from slab_kmem_cache_release()) happens when the refcount of
embedded kobject drops to zero. That's fine, since all references
to data structures in module's memory are already gone by the time
kmem_cache_destroy() returns. That, however, relies upon the struct
kmem_cache itself not being in module's memory; getting it unmapped
before slab_kmem_cache_release() has run needs to be avoided.
It's not hard to deal with, though. We need to make sure that
instance in a module will get to slab_kmem_cache_release() before the
module data gets freed. That's only a problem on sysfs setups -
otherwise it'll definitely be finished before kmem_cache_destroy()
returns.
Note that modules themselves have sysfs-exposed attributes,
so a similar problem already exists there. That's dealt with by
having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
reaching zero. Let's make use of that - have static-duration-in-module
kmem_cache instances grab a reference to that kobject upon setup and
drop it in the end of slab_kmem_cache_release().
Let setup helpers store the kobject to be pinned in
kmem_cache_args->owner (for preallocated; if somebody manually sets it
for non-preallocated case, it'll be ignored). That would be
&THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
If sysfs is enabled and we are dealing with preallocated instance,
let create_cache() grab and stash that reference in kmem_cache->owner
and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
instance.
Costs:
* a bit (SLAB_PREALLOCATED) is stolen from slab_flags_t
* such caches can't be merged with anything preexisting (obviously)
and subsequent cache creations can't merge with static-in-module
ones. If you want them more mergable, don't use that technics.
* you can't do kmem_cache_setup()/kmem_cache_destroy()/kmem_cache_setup()
on the same instance. Just don't do that.
Al Viro (9):
static kmem_cache instances for core caches
allow static-duration kmem_cache in modules
VFS caches: switch from runtime_const() machinery to slab-static.h
make inode_cache statically allocated
make mnt_cache statically allocated
make bh_cachep statically allocated
make seq_file_cache statically allocated
make thread component caches (fs_cachep, files_cachep, etc.)
statically allocated
make ufs_inode_cache statically allocated
Kbuild | 14 ++++++-
fs/buffer.c | 6 ++-
fs/dcache.c | 8 ++--
fs/file_table.c | 40 ++++++++----------
fs/inode.c | 6 ++-
fs/namei.c | 16 +++----
fs/namespace.c | 6 ++-
fs/seq_file.c | 6 ++-
fs/ufs/super.c | 9 ++--
include/asm-generic/vmlinux.lds.h | 6 +--
include/linux/fdtable.h | 3 +-
include/linux/fs_struct.h | 3 +-
include/linux/signal.h | 3 +-
include/linux/slab-static.h | 69 +++++++++++++++++++++++++++++++
include/linux/slab.h | 11 +++++
kernel/fork.c | 37 ++++++++++-------
mm/kmem_cache_size.c | 20 +++++++++
mm/slab.h | 1 +
mm/slab_common.c | 49 ++++++++++++++--------
mm/slub.c | 7 ++++
20 files changed, 231 insertions(+), 89 deletions(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
--
2.47.3
Al Viro (10):
static kmem_cache instances for core caches: infrastructure
static kmem_cache instances for core caches: setup primitives
allow preallocated kmem_cache instances in modules
VFS caches: switch from runtime_const() machinery to slab-static.h
make inode_cache statically allocated
make mnt_cache statically allocated
make bh_cachep statically allocated
make seq_file_cache statically allocated
make thread component caches (fs_cachep, files_cachep, etc.)
statically allocated
make ufs_inode_cache statically allocated
Kbuild | 14 ++++++-
fs/buffer.c | 6 ++-
fs/dcache.c | 8 ++--
fs/file_table.c | 40 ++++++++----------
fs/inode.c | 6 ++-
fs/namei.c | 16 +++----
fs/namespace.c | 6 ++-
fs/seq_file.c | 6 ++-
fs/ufs/super.c | 9 ++--
include/asm-generic/vmlinux.lds.h | 6 +--
include/linux/fdtable.h | 3 +-
include/linux/fs_struct.h | 3 +-
include/linux/signal.h | 3 +-
include/linux/slab-static.h | 69 +++++++++++++++++++++++++++++++
include/linux/slab.h | 11 +++++
kernel/fork.c | 37 ++++++++++-------
mm/kmem_cache_size.c | 20 +++++++++
mm/slab.h | 1 +
mm/slab_common.c | 50 +++++++++++++++-------
mm/slub.c | 27 +++++++-----
20 files changed, 242 insertions(+), 99 deletions(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
--
2.47.3
^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC PATCH v3 01/10] static kmem_cache instances for core caches: infrastructure
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 02/10] static kmem_cache instances for core caches: setup primitives Al Viro
` (9 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
kmem_cache_create() and friends create new instances of
struct kmem_cache and return pointers to those. Quite a few things in
core kernel are allocated from such caches; each allocation involves
dereferencing an assign-once pointer and for sufficiently hot ones that
dereferencing does show in profiles.
There had been patches floating around switching some of those
to runtime_const infrastructure. Unfortunately, it's arch-specific
and most of the architectures lack it.
There's an alternative approach applicable at least to the caches
that are never destroyed, which covers a lot of them. No matter what,
runtime_const for pointers is not going to be faster than plain &,
so if we had struct kmem_cache instances with static storage duration, we
would be at least no worse off than we are with runtime_const variants.
There are obstacles to doing that, but they turn out to be easy
to deal with.
First of all, struct kmem_cache is opaque for anything outside
of a few files in mm/*; that avoids serious headache with header dependencies,
etc., and it's not something we want to lose.
Solution: struct kmem_cache_opaque, with the size and alignment
identical to struct kmem_cache. Calculation of size and alignment can be
done via the same mechanism we use for asm-offsets.h and rq-offsets.h,
with build-time check for mismatches. With that done, we get an opaque type
defined in linux/slab-static.h that can be used for declaring those caches.
In linux/slab.h we add a forward declaration of kmem_cache_opaque +
helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
into the corresponding pointer to kmem_cache.
At that point we can't actually *do* anything with those statically
allocated instances - the primitives for setting them up are going to be
added in the next commits. Declarations of those primitives will also go
into linux/slab-static.h.
Note that this header is needed only in places that define and
initialize statically allocated kmem_cache instances; users of such
instances need only slab.h.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Kbuild | 14 +++++++++++++-
include/linux/slab-static.h | 13 +++++++++++++
include/linux/slab.h | 6 ++++++
mm/kmem_cache_size.c | 20 ++++++++++++++++++++
mm/slub.c | 7 +++++++
5 files changed, 59 insertions(+), 1 deletion(-)
create mode 100644 include/linux/slab-static.h
create mode 100644 mm/kmem_cache_size.c
diff --git a/Kbuild b/Kbuild
index a6a0192dea08..64f29f1f0e71 100644
--- a/Kbuild
+++ b/Kbuild
@@ -45,6 +45,17 @@ kernel/sched/rq-offsets.s: $(offsets-file)
$(rq-offsets-file): kernel/sched/rq-offsets.s FORCE
$(call filechk,offsets,__RQ_OFFSETS_H__)
+# generate kmem_cache_size.h
+
+kmem_cache_size-file := include/generated/kmem_cache_size.h
+
+targets += mm/kmem_cache_size.s
+
+mm/kmem_cache_size.s: $(rq-offsets-file)
+
+$(kmem_cache_size-file): mm/kmem_cache_size.s FORCE
+ $(call filechk,offsets,__KMEM_CACHE_SIZE_H__)
+
# Check for missing system calls
missing-syscalls-file := .tmp_missing-syscalls$(missing_syscalls_instance)
@@ -58,7 +69,8 @@ $(missing-syscalls-file): scripts/checksyscalls.sh $(rq-offsets-file) FORCE
$(call if_changed_dep,syscalls)
PHONY += missing-syscalls
-missing-syscalls: $(missing-syscalls-file)
+missing-syscalls: $(missing-syscalls-file) $(kmem_cache_size-file)
+ $(call cmd,syscalls)
# Check the manual modification of atomic headers
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
new file mode 100644
index 000000000000..07aca67facee
--- /dev/null
+++ b/include/linux/slab-static.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SLAB_STATIC_H
+#define _LINUX_SLAB_STATIC_H
+
+#include <linux/init.h>
+#include <generated/kmem_cache_size.h>
+
+/* same size and alignment as struct kmem_cache: */
+struct kmem_cache_opaque {
+ unsigned char opaque[KMEM_CACHE_SIZE];
+} __aligned(KMEM_CACHE_ALIGN);
+
+#endif
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2b5ab488e96b..a43d31eec06c 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -265,11 +265,17 @@ enum _slab_flag_bits {
struct list_lru;
struct mem_cgroup;
+struct kmem_cache_opaque;
/*
* struct kmem_cache related prototypes
*/
bool slab_is_available(void);
+static inline struct kmem_cache *to_kmem_cache(struct kmem_cache_opaque *p)
+{
+ return (struct kmem_cache *)p;
+}
+
/**
* struct kmem_cache_args - Less common arguments for kmem_cache_create()
*
diff --git a/mm/kmem_cache_size.c b/mm/kmem_cache_size.c
new file mode 100644
index 000000000000..1ddbfa41a507
--- /dev/null
+++ b/mm/kmem_cache_size.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generate definitions needed by the preprocessor.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#define COMPILE_OFFSETS
+#include <linux/kbuild.h>
+#include "slab.h"
+
+int main(void)
+{
+ /* The constants to put into include/generated/kmem_cache_size.h */
+ DEFINE(KMEM_CACHE_SIZE, sizeof(struct kmem_cache));
+ DEFINE(KMEM_CACHE_ALIGN, __alignof(struct kmem_cache));
+ /* End of constants */
+
+ return 0;
+}
diff --git a/mm/slub.c b/mm/slub.c
index a2bf3756ca7d..c0765173911d 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -50,6 +50,7 @@
#include <linux/irq_work.h>
#include <linux/kprobes.h>
#include <linux/debugfs.h>
+#include <linux/slab-static.h>
#include <trace/events/kmem.h>
#include "internal.h"
@@ -8484,6 +8485,12 @@ void __init kmem_cache_init(void)
boot_kmem_cache_node;
int node;
+ /* verify that kmem_cache_opaque is correct */
+ BUILD_BUG_ON(sizeof(struct kmem_cache) !=
+ sizeof(struct kmem_cache_opaque));
+ BUILD_BUG_ON(__alignof(struct kmem_cache) !=
+ __alignof(struct kmem_cache_opaque));
+
if (debug_guardpage_minorder())
slub_max_order = 0;
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 02/10] static kmem_cache instances for core caches: setup primitives
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 01/10] static kmem_cache instances for core caches: infrastructure Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 03/10] allow preallocated kmem_cache instances in modules Al Viro
` (8 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Teach the real constructor of kmem_cache needs to deal with preallocated
instances and provide wrappers parallel to kmem_cache_create() and friends.
That turns out to be easy - we already pass an obscene amount of optional
arguments via struct kmem_cache_args, so we can stash the pointer to
preallocated instance in there.
* add struct kmem_cache_args.preallocated - a pointer to preallocated
struct kmem_cache instance into kmem_cache_args. If it's non-NULL,
__kmem_cache_create_args() will set the supplied instance up instead
of allocating a new one.
* new struct kmem_cache.flags bit - SLAB_PREALLOCATED. Set by
__kmem_cache_create_args() when it's asked to use a preallocated instance.
* create_cache(): do allocation (and, in case of failure, freeing) of
struct kmem_cache instance only if no preallocated one has been supplied.
* __kmem_cache_alias(): don't bother with aliases when setting a preallocated
instance up - we want this one and no other, TYVM... Note that such instance
may very well be mergeable - later kmem_cache_create() might decide to return
an alias for it.
* sysfs_slab_add() should treat all preallocated instances as self-named -
no "unique" (== size-and-flags-derived) names for those, any symlinks
from possible future aliases will use the cache's name as target. Think
what happens if two preallocated kmem_cache instances are set up to have
identical sizes and flags - "unique" names will be anything but. Since
the preallocated instance won't go away before possible future aliases,
there's no problem with using its proper name.
* add new wrappers for __kmem_cache_create_args(): kmem_cache_setup(),
kmem_cache_setup_usercopy(), KMEM_CACHE_SETUP(), KMEM_CACHE_SETUP_USERCOPY(),
corresponding to kmem_cache_create(), kmem_cache_create_usercopy(),
KMEM_CACHE() and KMEM_CACHE_USERCOPY() resp. A pointer to preallocated
instance is passed as the first argument, followed by the arguments
one would pass to corresponding kmem_cache constructor.
That covers the instances that never get destroyed. Quite a few
fall into that category, but there's a major exception - anything in
modules must be destroyed before the module gets removed. For example,
filesystems that have their inodes allocated from a private kmem_cache
can't make use of that technics for their inode allocations, etc.
It's not that hard to deal with, but for now let's just ban
including slab-static.h from modules.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/slab-static.h | 53 +++++++++++++++++++++++++++++++++++++
include/linux/slab.h | 4 +++
mm/slab_common.c | 33 ++++++++++++-----------
mm/slub.c | 20 +++++++-------
4 files changed, 84 insertions(+), 26 deletions(-)
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
index 07aca67facee..007fc0bd4e8c 100644
--- a/include/linux/slab-static.h
+++ b/include/linux/slab-static.h
@@ -5,9 +5,62 @@
#include <linux/init.h>
#include <generated/kmem_cache_size.h>
+#ifdef MODULE
+#error "can't use that in modules"
+#endif
+
/* same size and alignment as struct kmem_cache: */
struct kmem_cache_opaque {
unsigned char opaque[KMEM_CACHE_SIZE];
} __aligned(KMEM_CACHE_ALIGN);
+#define __KMEM_CACHE_SETUP(cache, name, size, flags, ...) \
+ __kmem_cache_create_args((name), (size), \
+ &(struct kmem_cache_args) { \
+ .preallocated = (cache), \
+ __VA_ARGS__}, (flags))
+
+static inline int
+kmem_cache_setup_usercopy(struct kmem_cache *s,
+ const char *name, unsigned int size,
+ unsigned int align, slab_flags_t flags,
+ unsigned int useroffset, unsigned int usersize,
+ void (*ctor)(void *))
+{
+ struct kmem_cache *res;
+ res = __KMEM_CACHE_SETUP(s, name, size, flags,
+ .align = align,
+ .ctor = ctor,
+ .useroffset = useroffset,
+ .usersize = usersize);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+ return 0;
+}
+
+static inline int
+kmem_cache_setup(struct kmem_cache *s,
+ const char *name, unsigned int size,
+ unsigned int align, slab_flags_t flags,
+ void (*ctor)(void *))
+{
+ struct kmem_cache *res;
+ res = __KMEM_CACHE_SETUP(s, name, size, flags,
+ .align = align,
+ .ctor = ctor);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+ return 0;
+}
+
+#define KMEM_CACHE_SETUP(s, __struct, __flags) \
+ __KMEM_CACHE_SETUP((s), #__struct, sizeof(struct __struct), (__flags), \
+ .align = __alignof__(struct __struct))
+
+#define KMEM_CACHE_SETUP_USERCOPY(s, __struct, __flags, __field) \
+ __KMEM_CACHE_SETUP((s), #__struct, sizeof(struct __struct), (__flags), \
+ .align = __alignof__(struct __struct), \
+ .useroffset = offsetof(struct __struct, __field), \
+ .usersize = sizeof_field(struct __struct, __field))
+
#endif
diff --git a/include/linux/slab.h b/include/linux/slab.h
index a43d31eec06c..ec68aabf98df 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -62,6 +62,7 @@ enum _slab_flag_bits {
#if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
_SLAB_OBJ_EXT_IN_OBJ,
#endif
+ _SLAB_PREALLOCATED,
_SLAB_FLAGS_LAST_BIT
};
@@ -248,6 +249,8 @@ enum _slab_flag_bits {
#define SLAB_OBJ_EXT_IN_OBJ __SLAB_FLAG_UNUSED
#endif
+#define SLAB_PREALLOCATED __SLAB_FLAG_BIT(_SLAB_PREALLOCATED)
+
/*
* ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
*
@@ -378,6 +381,7 @@ struct kmem_cache_args {
* %0 means no sheaves will be created.
*/
unsigned int sheaf_capacity;
+ struct kmem_cache *preallocated;
};
struct kmem_cache *__kmem_cache_create_args(const char *name,
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 8b661fff5eed..5b6aaa96d68d 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -234,33 +234,30 @@ static struct kmem_cache *create_cache(const char *name,
struct kmem_cache_args *args,
slab_flags_t flags)
{
- struct kmem_cache *s;
+ struct kmem_cache *s = args->preallocated;
int err;
/* If a custom freelist pointer is requested make sure it's sane. */
- err = -EINVAL;
if (args->use_freeptr_offset &&
(args->freeptr_offset >= object_size ||
(!(flags & SLAB_TYPESAFE_BY_RCU) && !args->ctor) ||
!IS_ALIGNED(args->freeptr_offset, __alignof__(freeptr_t))))
- goto out;
+ return ERR_PTR(-EINVAL);
- err = -ENOMEM;
- s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
- if (!s)
- goto out;
+ if (!s) {
+ s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
+ if (!s)
+ return ERR_PTR(-ENOMEM);
+ }
err = do_kmem_cache_create(s, name, object_size, args, flags);
- if (err)
- goto out_free_cache;
-
+ if (unlikely(err)) {
+ if (!args->preallocated)
+ kmem_cache_free(kmem_cache, s);
+ return ERR_PTR(err);
+ }
s->refcount = 1;
list_add(&s->list, &slab_caches);
return s;
-
-out_free_cache:
- kmem_cache_free(kmem_cache, s);
-out:
- return ERR_PTR(err);
}
static struct kmem_cache *
@@ -269,6 +266,9 @@ __kmem_cache_alias(const char *name, unsigned int size, slab_flags_t flags,
{
struct kmem_cache *s;
+ if (flags & SLAB_PREALLOCATED) // no aliases - we are using this one
+ return NULL;
+
s = find_mergeable(size, flags, name, args);
if (s) {
if (sysfs_slab_alias(s, name))
@@ -366,6 +366,9 @@ struct kmem_cache *__kmem_cache_create_args(const char *name,
object_size - args->usersize < args->useroffset))
args->usersize = args->useroffset = 0;
+ if (args->preallocated)
+ flags |= SLAB_PREALLOCATED;
+
s = __kmem_cache_alias(name, object_size, flags, args);
if (s)
goto out_unlock;
diff --git a/mm/slub.c b/mm/slub.c
index c0765173911d..eee68e0ad7ed 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -9593,18 +9593,16 @@ static int sysfs_slab_add(struct kmem_cache *s)
int err;
const char *name;
struct kset *kset = cache_kset(s);
- int unmergeable = slab_unmergeable(s);
+ bool no_symlink = slab_unmergeable(s);
- if (!unmergeable && disable_higher_order_debug &&
+ if (s->flags & SLAB_PREALLOCATED)
+ no_symlink = true;
+
+ if (!no_symlink && disable_higher_order_debug &&
(slub_debug & DEBUG_METADATA_FLAGS))
- unmergeable = 1;
+ no_symlink = true;
- if (unmergeable) {
- /*
- * Slabcache can never be merged so we can use the name proper.
- * This is typically the case for debug situations. In that
- * case we can catch duplicate names easily.
- */
+ if (no_symlink) {
sysfs_remove_link(&slab_kset->kobj, s->name);
name = s->name;
} else {
@@ -9622,12 +9620,12 @@ static int sysfs_slab_add(struct kmem_cache *s)
if (err)
goto out;
- if (!unmergeable) {
+ if (!no_symlink) {
/* Setup first alias */
sysfs_slab_alias(s, s->name);
}
out:
- if (!unmergeable)
+ if (!no_symlink)
kfree(name);
return err;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 03/10] allow preallocated kmem_cache instances in modules
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 01/10] static kmem_cache instances for core caches: infrastructure Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 02/10] static kmem_cache instances for core caches: setup primitives Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 04/10] VFS caches: switch from runtime_const() machinery to slab-static.h Al Viro
` (7 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
We need to make sure that instance in a module will get to
slab_kmem_cache_release() before the module data gets freed. That's only
a problem on sysfs setups - otherwise it'll definitely be finished before
kmem_cache_destroy() returns.
Note that modules themselves have sysfs-exposed attributes,
so a similar problem already exists there. That's dealt with by
having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
reaching zero. Let's make use of that - have static-duration-in-module
kmem_cache instances grab a reference to that kobject upon setup and
drop it in the end of slab_kmem_cache_release().
Let setup helpers store the kobject to be pinned in
kmem_cache_args->owner (for preallocated; if somebody manually sets it
for non-preallocated case, it'll be ignored). That would be
&THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
If sysfs is enabled and we are dealing with preallocated instance,
let create_cache() grab and stash that reference in kmem_cache->owner
and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
instance.
Preallocated kmem_cache instances in modules are forcibly made
non-mergable - any subsequent alias could outlive the module (and module's
.data) by arbitrary long time. If you really want your (modular) cache
to be mergable, just have it dynamically allocated.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/slab-static.h | 11 +++++++----
include/linux/slab.h | 1 +
mm/slab.h | 1 +
mm/slab_common.c | 19 +++++++++++++++++--
4 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/include/linux/slab-static.h b/include/linux/slab-static.h
index 007fc0bd4e8c..16d1564b4a4b 100644
--- a/include/linux/slab-static.h
+++ b/include/linux/slab-static.h
@@ -5,18 +5,21 @@
#include <linux/init.h>
#include <generated/kmem_cache_size.h>
-#ifdef MODULE
-#error "can't use that in modules"
-#endif
-
/* same size and alignment as struct kmem_cache: */
struct kmem_cache_opaque {
unsigned char opaque[KMEM_CACHE_SIZE];
} __aligned(KMEM_CACHE_ALIGN);
+#ifdef MODULE
+#define THIS_MODULE_KOBJ &THIS_MODULE->mkobj.kobj
+#else
+#define THIS_MODULE_KOBJ NULL
+#endif
+
#define __KMEM_CACHE_SETUP(cache, name, size, flags, ...) \
__kmem_cache_create_args((name), (size), \
&(struct kmem_cache_args) { \
+ .owner = THIS_MODULE_KOBJ, \
.preallocated = (cache), \
__VA_ARGS__}, (flags))
diff --git a/include/linux/slab.h b/include/linux/slab.h
index ec68aabf98df..c95ad771ece2 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -382,6 +382,7 @@ struct kmem_cache_args {
*/
unsigned int sheaf_capacity;
struct kmem_cache *preallocated;
+ struct kobject *owner;
};
struct kmem_cache *__kmem_cache_create_args(const char *name,
diff --git a/mm/slab.h b/mm/slab.h
index bf2f87acf5e3..8b1db0d03226 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -219,6 +219,7 @@ struct kmem_cache {
struct list_head list; /* List of slab caches */
#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
+ struct kobject *owner; /* keep that pinned while alive */
#endif
#ifdef CONFIG_SLAB_FREELIST_HARDENED
unsigned long random;
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 5b6aaa96d68d..1717c79d92be 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -255,6 +255,12 @@ static struct kmem_cache *create_cache(const char *name,
kmem_cache_free(kmem_cache, s);
return ERR_PTR(err);
}
+#ifdef CONFIG_SYSFS
+ if (flags & SLAB_PREALLOCATED) {
+ s->owner = args->owner;
+ kobject_get(s->owner);
+ }
+#endif
s->refcount = 1;
list_add(&s->list, &slab_caches);
return s;
@@ -366,8 +372,11 @@ struct kmem_cache *__kmem_cache_create_args(const char *name,
object_size - args->usersize < args->useroffset))
args->usersize = args->useroffset = 0;
- if (args->preallocated)
+ if (args->preallocated) {
flags |= SLAB_PREALLOCATED;
+ if (args->owner)
+ flags |= SLAB_NO_MERGE;
+ }
s = __kmem_cache_alias(name, object_size, flags, args);
if (s)
@@ -524,7 +533,13 @@ void slab_kmem_cache_release(struct kmem_cache *s)
{
__kmem_cache_release(s);
kfree_const(s->name);
- kmem_cache_free(kmem_cache, s);
+ if (!(s->flags & SLAB_PREALLOCATED)) {
+ kmem_cache_free(kmem_cache, s);
+ return;
+ }
+#ifdef CONFIG_SYSFS
+ kobject_put(s->owner);
+#endif
}
void kmem_cache_destroy(struct kmem_cache *s)
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 04/10] VFS caches: switch from runtime_const() machinery to slab-static.h
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (2 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 03/10] allow preallocated kmem_cache instances in modules Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 05/10] make inode_cache statically allocated Al Viro
` (6 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Four VFS caches are currently playing games with runtime_const() to
reduce the overhead of pointer traversals - dentry, file, backing_file
and filename. All of these kmem_cache instances can be allocated
statically now, getting rid of runtime_const() games.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 8 +++----
fs/file_table.c | 40 ++++++++++++++-----------------
fs/namei.c | 16 ++++++-------
include/asm-generic/vmlinux.lds.h | 6 +----
4 files changed, 31 insertions(+), 39 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 2c61aeea41f4..e2feea82682a 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -32,6 +32,7 @@
#include <linux/bit_spinlock.h>
#include <linux/rculist_bl.h>
#include <linux/list_lru.h>
+#include <linux/slab-static.h>
#include "internal.h"
#include "mount.h"
@@ -86,8 +87,8 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
EXPORT_SYMBOL(rename_lock);
-static struct kmem_cache *__dentry_cache __ro_after_init;
-#define dentry_cache runtime_const_ptr(__dentry_cache)
+static struct kmem_cache_opaque __dentry_cache;
+#define dentry_cache to_kmem_cache(&__dentry_cache)
const struct qstr empty_name = QSTR_INIT("", 0);
EXPORT_SYMBOL(empty_name);
@@ -3362,10 +3363,9 @@ static void __init dcache_init(void)
* but it is probably not worth it because of the cache nature
* of the dcache.
*/
- __dentry_cache = KMEM_CACHE_USERCOPY(dentry,
+ KMEM_CACHE_SETUP_USERCOPY(dentry_cache, dentry,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_ACCOUNT,
d_shortname.string);
- runtime_const_init(ptr, __dentry_cache);
/* Hash may have been set up in dcache_init_early */
if (!hashdist)
diff --git a/fs/file_table.c b/fs/file_table.c
index 16e52e7fc2ac..3844bc9f0e0a 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -27,11 +27,10 @@
#include <linux/task_work.h>
#include <linux/swap.h>
#include <linux/kmemleak.h>
+#include <linux/slab-static.h>
#include <linux/atomic.h>
-#include <asm/runtime-const.h>
-
#include "internal.h"
/* sysctl tunables... */
@@ -40,10 +39,10 @@ static struct files_stat_struct files_stat = {
};
/* SLAB cache for file structures */
-static struct kmem_cache *__filp_cache __ro_after_init;
-#define filp_cache runtime_const_ptr(__filp_cache)
-static struct kmem_cache *__bfilp_cache __ro_after_init;
-#define bfilp_cache runtime_const_ptr(__bfilp_cache)
+static struct kmem_cache_opaque file_cache;
+static struct kmem_cache_opaque backing_file_cache;
+#define filp_cache to_kmem_cache(&file_cache)
+#define bfilp_cache to_kmem_cache(&backing_file_cache)
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
@@ -629,22 +628,19 @@ void fput_close(struct file *file)
void __init files_init(void)
{
- struct kmem_cache_args args = {
- .use_freeptr_offset = true,
- .freeptr_offset = offsetof(struct file, f_freeptr),
- };
-
- __filp_cache = kmem_cache_create("filp", sizeof(struct file), &args,
- SLAB_HWCACHE_ALIGN | SLAB_PANIC |
- SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU);
- runtime_const_init(ptr, __filp_cache);
-
- args.freeptr_offset = offsetof(struct backing_file, bf_freeptr);
- __bfilp_cache = kmem_cache_create("bfilp", sizeof(struct backing_file),
- &args, SLAB_HWCACHE_ALIGN | SLAB_PANIC |
- SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU);
- runtime_const_init(ptr, __bfilp_cache);
-
+ __KMEM_CACHE_SETUP(filp_cache, "filp", sizeof(struct file),
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+ SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
+ .use_freeptr_offset = true,
+ .freeptr_offset = offsetof(struct file,
+ f_freeptr));
+
+ __KMEM_CACHE_SETUP(bfilp_cache, "bfilp", sizeof(struct backing_file),
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+ SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
+ .use_freeptr_offset = true,
+ .freeptr_offset = offsetof(struct backing_file,
+ bf_freeptr));
percpu_counter_init(&nr_files, 0, GFP_KERNEL);
}
diff --git a/fs/namei.c b/fs/namei.c
index 4787244ca4a7..13d95881e921 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -40,8 +40,7 @@
#include <linux/bitops.h>
#include <linux/init_task.h>
#include <linux/uaccess.h>
-
-#include <asm/runtime-const.h>
+#include <linux/slab-static.h>
#include "internal.h"
#include "mount.h"
@@ -126,15 +125,16 @@
*/
/* SLAB cache for struct filename instances */
-static struct kmem_cache *__names_cache __ro_after_init;
-#define names_cache runtime_const_ptr(__names_cache)
+static struct kmem_cache_opaque __names_cache;
+#define names_cache to_kmem_cache(&__names_cache)
void __init filename_init(void)
{
- __names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
- EMBEDDED_NAME_MAX, NULL);
- runtime_const_init(ptr, __names_cache);
+ kmem_cache_setup_usercopy(names_cache, "names_cache",
+ sizeof(struct filename), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ offsetof(struct filename, iname),
+ EMBEDDED_NAME_MAX, NULL);
}
static inline struct filename *alloc_filename(void)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 60c8c22fd3e4..4719269086c7 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -966,11 +966,7 @@
#define RUNTIME_CONST_VARIABLES \
RUNTIME_CONST(shift, d_hash_shift) \
- RUNTIME_CONST(ptr, dentry_hashtable) \
- RUNTIME_CONST(ptr, __dentry_cache) \
- RUNTIME_CONST(ptr, __names_cache) \
- RUNTIME_CONST(ptr, __filp_cache) \
- RUNTIME_CONST(ptr, __bfilp_cache)
+ RUNTIME_CONST(ptr, dentry_hashtable)
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
#define KUNIT_TABLE() \
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 05/10] make inode_cache statically allocated
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (3 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 04/10] VFS caches: switch from runtime_const() machinery to slab-static.h Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 06/10] make mnt_cache " Al Viro
` (5 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/inode.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 62c579a0cf7d..1c657ac99084 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -23,6 +23,7 @@
#include <linux/rw_hint.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/slab-static.h>
#include <trace/events/writeback.h>
#define CREATE_TRACE_POINTS
#include <trace/events/timestamp.h>
@@ -76,7 +77,8 @@ EXPORT_SYMBOL(empty_aops);
static DEFINE_PER_CPU(unsigned long, nr_inodes);
static DEFINE_PER_CPU(unsigned long, nr_unused);
-static struct kmem_cache *inode_cachep __ro_after_init;
+static struct kmem_cache_opaque inode_cache;
+#define inode_cachep to_kmem_cache(&inode_cache)
static long get_nr_inodes(void)
{
@@ -2598,7 +2600,7 @@ void __init inode_init_early(void)
void __init inode_init(void)
{
/* inode slab cache */
- inode_cachep = kmem_cache_create("inode_cache",
+ kmem_cache_setup(inode_cachep, "inode_cache",
sizeof(struct inode),
0,
(SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 06/10] make mnt_cache statically allocated
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (4 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 05/10] make inode_cache statically allocated Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 07/10] make bh_cachep " Al Viro
` (4 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index f5905f4ec560..330ac43efb8d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -34,6 +34,7 @@
#include <linux/mnt_idmapping.h>
#include <linux/pidfs.h>
#include <linux/nstree.h>
+#include <linux/slab-static.h>
#include "pnode.h"
#include "internal.h"
@@ -79,7 +80,8 @@ static u64 mnt_id_ctr = MNT_UNIQUE_ID_OFFSET;
static struct hlist_head *mount_hashtable __ro_after_init;
static struct hlist_head *mountpoint_hashtable __ro_after_init;
-static struct kmem_cache *mnt_cache __ro_after_init;
+static struct kmem_cache_opaque __mnt_cache;
+#define mnt_cache to_kmem_cache(&__mnt_cache)
static DECLARE_RWSEM(namespace_sem);
static HLIST_HEAD(unmounted); /* protected by namespace_sem */
static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
@@ -6234,7 +6236,7 @@ void __init mnt_init(void)
{
int err;
- mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
+ kmem_cache_setup(mnt_cache, "mnt_cache", sizeof(struct mount),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
mount_hashtable = alloc_large_system_hash("Mount-cache",
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 07/10] make bh_cachep statically allocated
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (5 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 06/10] make mnt_cache " Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 08/10] make seq_file_cache " Al Viro
` (3 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/buffer.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index b0b3792b1496..e834f7091f51 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -51,6 +51,7 @@
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/sched/isolation.h>
+#include <linux/slab-static.h>
#include "internal.h"
@@ -2906,7 +2907,8 @@ EXPORT_SYMBOL(try_to_free_buffers);
/*
* Buffer-head allocation
*/
-static struct kmem_cache *bh_cachep __ro_after_init;
+static struct kmem_cache_opaque bh_cache;
+#define bh_cachep to_kmem_cache(&bh_cache)
/*
* Once the number of bh's in the machine exceeds this level, we start
@@ -3065,7 +3067,7 @@ void __init buffer_init(void)
unsigned long nrpages;
int ret;
- bh_cachep = KMEM_CACHE(buffer_head,
+ KMEM_CACHE_SETUP(bh_cachep, buffer_head,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC);
/*
* Limit the bh occupancy to 10% of ZONE_NORMAL
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 08/10] make seq_file_cache statically allocated
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (6 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 07/10] make bh_cachep " Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 09/10] make thread component caches (fs_cachep, files_cachep, etc.) " Al Viro
` (2 subsequent siblings)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/seq_file.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 4745db2a34d1..7cb40ae83f9b 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -20,11 +20,13 @@
#include <linux/printk.h>
#include <linux/string_helpers.h>
#include <linux/uio.h>
+#include <linux/slab-static.h>
#include <linux/uaccess.h>
#include <asm/page.h>
-static struct kmem_cache *seq_file_cache __ro_after_init;
+static struct kmem_cache_opaque __seq_file_cache;
+#define seq_file_cache to_kmem_cache(&__seq_file_cache)
static void seq_set_overflow(struct seq_file *m)
{
@@ -1140,5 +1142,5 @@ EXPORT_SYMBOL(seq_hlist_next_percpu);
void __init seq_file_init(void)
{
- seq_file_cache = KMEM_CACHE(seq_file, SLAB_ACCOUNT|SLAB_PANIC);
+ KMEM_CACHE_SETUP(seq_file_cache, seq_file, SLAB_ACCOUNT|SLAB_PANIC);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 09/10] make thread component caches (fs_cachep, files_cachep, etc.) statically allocated
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (7 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 08/10] make seq_file_cache " Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 10/10] make ufs_inode_cache " Al Viro
2026-06-23 8:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Vlastimil Babka (SUSE)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
All of them are created in kernel/fork.c, might as well convert all
at once...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/fdtable.h | 3 ++-
include/linux/fs_struct.h | 3 ++-
include/linux/signal.h | 3 ++-
kernel/fork.c | 37 +++++++++++++++++++++----------------
4 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index c45306a9f007..f2d553f99c58 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -113,6 +113,7 @@ int iterate_fd(struct files_struct *, unsigned,
extern int close_fd(unsigned int fd);
extern struct file *file_close_fd(unsigned int fd);
-extern struct kmem_cache *files_cachep;
+extern struct kmem_cache_opaque files_cache;
+#define files_cachep to_kmem_cache(&files_cache)
#endif /* __LINUX_FDTABLE_H */
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 0070764b790a..e8c9fac5b7b7 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -15,7 +15,8 @@ struct fs_struct {
struct path root, pwd;
} __randomize_layout;
-extern struct kmem_cache *fs_cachep;
+extern struct kmem_cache_opaque fs_struct_cache;
+#define fs_cachep to_kmem_cache(&fs_struct_cache)
extern void exit_fs(struct task_struct *);
extern void set_fs_root(struct fs_struct *, const struct path *);
diff --git a/include/linux/signal.h b/include/linux/signal.h
index f19816832f05..a0c7fee8b22a 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -323,7 +323,8 @@ static inline void disallow_signal(int sig)
kernel_sigaction(sig, SIG_IGN);
}
-extern struct kmem_cache *sighand_cachep;
+extern struct kmem_cache_opaque sighand_cache;
+#define sighand_cachep to_kmem_cache(&sighand_cache)
extern bool unhandled_signal(struct task_struct *tsk, int sig);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8ac38beae360..618f19bb482a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -111,6 +111,7 @@
#include <linux/unwind_deferred.h>
#include <linux/pgalloc.h>
#include <linux/uaccess.h>
+#include <linux/slab-static.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -180,7 +181,8 @@ void __weak arch_release_task_struct(struct task_struct *tsk)
{
}
-static struct kmem_cache *task_struct_cachep;
+static struct kmem_cache_opaque task_struct_cache;
+#define task_struct_cachep to_kmem_cache(&task_struct_cache)
static inline struct task_struct *alloc_task_struct_node(int node)
{
@@ -425,7 +427,8 @@ static void free_thread_stack(struct task_struct *tsk)
#else /* !(THREAD_SIZE >= PAGE_SIZE) */
-static struct kmem_cache *thread_stack_cache;
+static struct kmem_cache_opaque __thread_stack_cache;
+#define thread_stack_cache to_kmem_cache(&__thread_stack_cache)
static void thread_stack_free_rcu(struct rcu_head *rh)
{
@@ -456,29 +459,31 @@ static void free_thread_stack(struct task_struct *tsk)
void thread_stack_cache_init(void)
{
- thread_stack_cache = kmem_cache_create_usercopy("thread_stack",
- THREAD_SIZE, THREAD_SIZE, 0, 0,
+ kmem_cache_setup_usercopy(thread_stack_cache, "thread_stack",
+ THREAD_SIZE, THREAD_SIZE,
+ SLAB_PANIC, 0,
THREAD_SIZE, NULL);
- BUG_ON(thread_stack_cache == NULL);
}
#endif /* THREAD_SIZE >= PAGE_SIZE */
#endif /* CONFIG_VMAP_STACK */
/* SLAB cache for signal_struct structures (tsk->signal) */
-static struct kmem_cache *signal_cachep;
+static struct kmem_cache_opaque signal_cache;
+#define signal_cachep to_kmem_cache(&signal_cache)
/* SLAB cache for sighand_struct structures (tsk->sighand) */
-struct kmem_cache *sighand_cachep;
+struct kmem_cache_opaque sighand_cache;
/* SLAB cache for files_struct structures (tsk->files) */
-struct kmem_cache *files_cachep;
+struct kmem_cache_opaque files_cache;
/* SLAB cache for fs_struct structures (tsk->fs) */
-struct kmem_cache *fs_cachep;
+struct kmem_cache_opaque fs_struct_cache;
/* SLAB cache for mm_struct structures (tsk->mm) */
-static struct kmem_cache *mm_cachep;
+static struct kmem_cache_opaque mm_cache;
+#define mm_cachep to_kmem_cache(&mm_cache)
static void account_kernel_stack(struct task_struct *tsk, int account)
{
@@ -859,7 +864,7 @@ void __init fork_init(void)
/* create a slab on which task_structs can be allocated */
task_struct_whitelist(&useroffset, &usersize);
- task_struct_cachep = kmem_cache_create_usercopy("task_struct",
+ kmem_cache_setup_usercopy(task_struct_cachep, "task_struct",
arch_task_struct_size, align,
SLAB_PANIC|SLAB_ACCOUNT,
useroffset, usersize, NULL);
@@ -3079,7 +3084,7 @@ void __init mm_cache_init(void)
*/
mm_size = sizeof(struct mm_struct) + cpumask_size() + mm_cid_size();
- mm_cachep = kmem_cache_create_usercopy("mm_struct",
+ kmem_cache_setup_usercopy(mm_cachep, "mm_struct",
mm_size, ARCH_MIN_MMSTRUCT_ALIGN,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
offsetof(struct mm_struct, saved_auxv),
@@ -3089,19 +3094,19 @@ void __init mm_cache_init(void)
void __init proc_caches_init(void)
{
- sighand_cachep = kmem_cache_create("sighand_cache",
+ kmem_cache_setup(sighand_cachep, "sighand_cache",
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU|
SLAB_ACCOUNT, sighand_ctor);
- signal_cachep = kmem_cache_create("signal_cache",
+ kmem_cache_setup(signal_cachep, "signal_cache",
sizeof(struct signal_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
- files_cachep = kmem_cache_create("files_cache",
+ kmem_cache_setup(files_cachep, "files_cache",
sizeof(struct files_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
- fs_cachep = kmem_cache_create("fs_cache",
+ kmem_cache_setup(fs_cachep, "fs_cache",
sizeof(struct fs_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC PATCH v3 10/10] make ufs_inode_cache statically allocated
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (8 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 09/10] make thread component caches (fs_cachep, files_cachep, etc.) " Al Viro
@ 2026-06-13 5:09 ` Al Viro
2026-06-23 8:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Vlastimil Babka (SUSE)
10 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-13 5:09 UTC (permalink / raw)
To: linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
A modular example I used for testing...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ufs/super.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index c4831a8b9b3f..72053bc9c8dc 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -90,6 +90,7 @@
#include <linux/log2.h>
#include <linux/seq_file.h>
#include <linux/iversion.h>
+#include <linux/slab-static.h>
#include "ufs_fs.h"
#include "ufs.h"
@@ -1353,7 +1354,8 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static struct kmem_cache * ufs_inode_cachep;
+static struct kmem_cache_opaque ufs_inode_cache;
+#define ufs_inode_cachep to_kmem_cache(&ufs_inode_cache)
static struct inode *ufs_alloc_inode(struct super_block *sb)
{
@@ -1383,16 +1385,13 @@ static void init_once(void *foo)
static int __init init_inodecache(void)
{
- ufs_inode_cachep = kmem_cache_create_usercopy("ufs_inode_cache",
+ return kmem_cache_setup_usercopy(ufs_inode_cachep, "ufs_inode_cache",
sizeof(struct ufs_inode_info), 0,
(SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT),
offsetof(struct ufs_inode_info, i_u1.i_symlink),
sizeof_field(struct ufs_inode_info,
i_u1.i_symlink),
init_once);
- if (ufs_inode_cachep == NULL)
- return -ENOMEM;
- return 0;
}
static void destroy_inodecache(void)
--
2.47.3
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC PATCH v3 00/10] kmem_cache instances with static storage duration
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
` (9 preceding siblings ...)
2026-06-13 5:09 ` [RFC PATCH v3 10/10] make ufs_inode_cache " Al Viro
@ 2026-06-23 8:09 ` Vlastimil Babka (SUSE)
2026-06-24 0:48 ` Al Viro
10 siblings, 1 reply; 52+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-06-23 8:09 UTC (permalink / raw)
To: Al Viro, linux-mm
Cc: Vlastimil Babka, Harry Yoo, linux-fsdevel, Linus Torvalds,
Christian Brauner, Jan Kara, Mateusz Guzik, linux-kernel
On 6/13/26 07:09, Al Viro wrote:
> Changes since v2:
> * fixed the braindamage in /sys/kernel/slab (any statically allocated
> caches should just use their name for subdirectory, whether they are mergable
> or not)
> * infrastructure bits slightly reordered and carved in hopefully saner
> way.
> * rebased to 7.1-rc7.
>
> Changes since v1:
> * milder restrictions on mergability (non-modular static cache
> can be used as alias for later dynamic ones)
> * consolidated conversions into fewer commits
> * rebased to 7.1-rc6.
>
> Branch lives in
> git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.kmem_cache_static
> individual patches in followups.
>
> Please, review. It appears to work; the impact on merging is very small -
> on the testbox here (251 distinct aliases) mainline gets 140 kmem_cache
> instances and this series gets 142 - fs_cachep and names_cache get split
> from the group of 192-byte caches. Considering the contents and use patterns
> for those two... we might be better off that way, actually.
>
> kmem_cache_create() and friends create new instances of
> struct kmem_cache and return pointers to those. Quite a few things in
> core kernel are allocated from such caches; each allocation involves
> dereferencing an assign-once pointer and for sufficiently hot ones that
> dereferencing does show in profiles.
>
> There had been patches floating around switching some of those
> to runtime_const infrastructure. Unfortunately, it's arch-specific
> and most of the architectures lack it.
There's only a handful of architectures that would be considered performance
critical enough for us to care, right? So the question is which ones of
those lack it and would the effort to make them support it be smaller than
doing this? Also this covers slab only, but I'd expect runtime_const() would
have use cases also in other subsystems that wouldn't need
subsystem-specific changes?
> There's an alternative approach applicable at least to the caches
> that are never destroyed, which covers a lot of them. No matter what,
> runtime_const for pointers is not going to be faster than plain &,
> so if we had struct kmem_cache instances with static storage duration, we
> would be at least no worse off than we are with runtime_const variants.
But the argument for doing the static duration support is that it should be
faster, not just "not slower"? So is runtime_const equivalent or for some
fundamental reason it's slower than plain &?
Or is the advantage that static caches can support modules and runtime_const
can't?
> There are obstacles to doing that, but they turn out to be easy
> to deal with.
>
> 1) as it is, struct kmem_cache is opaque for anything outside of a few
> files in mm/*; that avoids serious headache with header dependencies,
> etc., and it's not something we want to lose. Solution: struct
> kmem_cache_opaque, with the size and alignment identical to struct
> kmem_cache. Calculation of size and alignment can be done via the same
> mechanism we use for asm-offsets.h and rq-offsets.h, with build-time
> check for mismatches. With that done, we get an opaque type defined in
> linux/slab-static.h that can be used for declaring those caches.
> In linux/slab.h we add a forward declaration of kmem_cache_opaque +
> helper (to_kmem_cache()) converting a pointer to kmem_cache_opaque
> into pointer to kmem_cache.
>
> 2) real constructor of kmem_cache needs to be taught to deal with
> preallocated instances. That turns out to be easy - we already pass an
> obscene amount of optional arguments via struct kmem_cache_args, so we
> can stash the pointer to preallocated instance in there. Changes in
> mm/slab_common.c are very minor - we should not merge preallocated caches
> with anything already created, use the instance passed to us instead of
> allocating a new one and we should not free them. That's it.
>
> A set of helpers parallel to kmem_cache_create() and friends
> (kmem_cache_setup(), etc.) is provided in the same linux/slab-static.h;
> generally, conversion affects only a few lines.
>
> Note that slab-static.h is needed only in places that create
> such instances; all users need only slab.h (and they can be modular,
> unlike runtime_const-based approach).
>
>
> That covers the instances that never get destroyed. Quite a few
> fall into that category, but there's a major exception - anything in
> modules must be destroyed before the module gets removed. Note that
> unlike runtime_constant-based approach, cache _uses_ in a module are
> fine - if kmem_cache_opaque instance is exported, its address is available
> to modules without any problems. It's caches _created_ in a module
So are there uses in modules of caches created in built-in code, which
therefore could not be changed to runtime_const?
> that offer an extra twist.
>
> Teaching kmem_cache_destroy() to skip actual freeing of given
> kmem_cache instance is trivial; the problem is that kmem_cache_destroy()
> may overlap with sysfs access to attributes of that cache. In that
> case kmem_cache_destroy() may return before the instance gets freed -
> freeing (from slab_kmem_cache_release()) happens when the refcount of
> embedded kobject drops to zero. That's fine, since all references
> to data structures in module's memory are already gone by the time
> kmem_cache_destroy() returns. That, however, relies upon the struct
> kmem_cache itself not being in module's memory; getting it unmapped
> before slab_kmem_cache_release() has run needs to be avoided.
>
> It's not hard to deal with, though. We need to make sure that
> instance in a module will get to slab_kmem_cache_release() before the
> module data gets freed. That's only a problem on sysfs setups -
> otherwise it'll definitely be finished before kmem_cache_destroy()
> returns.
>
> Note that modules themselves have sysfs-exposed attributes,
> so a similar problem already exists there. That's dealt with by
> having mod_sysfs_teardown() wait for refcount of module->mkobj.kobj
> reaching zero. Let's make use of that - have static-duration-in-module
> kmem_cache instances grab a reference to that kobject upon setup and
> drop it in the end of slab_kmem_cache_release().
>
> Let setup helpers store the kobject to be pinned in
> kmem_cache_args->owner (for preallocated; if somebody manually sets it
> for non-preallocated case, it'll be ignored). That would be
> &THIS_MODULE->mkobj.kobj for a module and NULL in built-in.
>
> If sysfs is enabled and we are dealing with preallocated instance,
> let create_cache() grab and stash that reference in kmem_cache->owner
> and let slab_kmem_cache_release() drop it instead of freeing kmem_cache
> instance.
>
>
> Costs:
> * a bit (SLAB_PREALLOCATED) is stolen from slab_flags_t
> * such caches can't be merged with anything preexisting (obviously)
> and subsequent cache creations can't merge with static-in-module
> ones. If you want them more mergable, don't use that technics.
> * you can't do kmem_cache_setup()/kmem_cache_destroy()/kmem_cache_setup()
> on the same instance. Just don't do that.
>
> Al Viro (9):
> static kmem_cache instances for core caches
> allow static-duration kmem_cache in modules
> VFS caches: switch from runtime_const() machinery to slab-static.h
> make inode_cache statically allocated
> make mnt_cache statically allocated
> make bh_cachep statically allocated
> make seq_file_cache statically allocated
> make thread component caches (fs_cachep, files_cachep, etc.)
> statically allocated
> make ufs_inode_cache statically allocated
>
> Kbuild | 14 ++++++-
> fs/buffer.c | 6 ++-
> fs/dcache.c | 8 ++--
> fs/file_table.c | 40 ++++++++----------
> fs/inode.c | 6 ++-
> fs/namei.c | 16 +++----
> fs/namespace.c | 6 ++-
> fs/seq_file.c | 6 ++-
> fs/ufs/super.c | 9 ++--
> include/asm-generic/vmlinux.lds.h | 6 +--
> include/linux/fdtable.h | 3 +-
> include/linux/fs_struct.h | 3 +-
> include/linux/signal.h | 3 +-
> include/linux/slab-static.h | 69 +++++++++++++++++++++++++++++++
> include/linux/slab.h | 11 +++++
> kernel/fork.c | 37 ++++++++++-------
> mm/kmem_cache_size.c | 20 +++++++++
> mm/slab.h | 1 +
> mm/slab_common.c | 49 ++++++++++++++--------
> mm/slub.c | 7 ++++
> 20 files changed, 231 insertions(+), 89 deletions(-)
> create mode 100644 include/linux/slab-static.h
> create mode 100644 mm/kmem_cache_size.c
>
> --
> 2.47.3
>
>
>
> Al Viro (10):
> static kmem_cache instances for core caches: infrastructure
> static kmem_cache instances for core caches: setup primitives
> allow preallocated kmem_cache instances in modules
> VFS caches: switch from runtime_const() machinery to slab-static.h
> make inode_cache statically allocated
> make mnt_cache statically allocated
> make bh_cachep statically allocated
> make seq_file_cache statically allocated
> make thread component caches (fs_cachep, files_cachep, etc.)
> statically allocated
> make ufs_inode_cache statically allocated
>
> Kbuild | 14 ++++++-
> fs/buffer.c | 6 ++-
> fs/dcache.c | 8 ++--
> fs/file_table.c | 40 ++++++++----------
> fs/inode.c | 6 ++-
> fs/namei.c | 16 +++----
> fs/namespace.c | 6 ++-
> fs/seq_file.c | 6 ++-
> fs/ufs/super.c | 9 ++--
> include/asm-generic/vmlinux.lds.h | 6 +--
> include/linux/fdtable.h | 3 +-
> include/linux/fs_struct.h | 3 +-
> include/linux/signal.h | 3 +-
> include/linux/slab-static.h | 69 +++++++++++++++++++++++++++++++
> include/linux/slab.h | 11 +++++
> kernel/fork.c | 37 ++++++++++-------
> mm/kmem_cache_size.c | 20 +++++++++
> mm/slab.h | 1 +
> mm/slab_common.c | 50 +++++++++++++++-------
> mm/slub.c | 27 +++++++-----
> 20 files changed, 242 insertions(+), 99 deletions(-)
> create mode 100644 include/linux/slab-static.h
> create mode 100644 mm/kmem_cache_size.c
>
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC PATCH v3 00/10] kmem_cache instances with static storage duration
2026-06-23 8:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Vlastimil Babka (SUSE)
@ 2026-06-24 0:48 ` Al Viro
0 siblings, 0 replies; 52+ messages in thread
From: Al Viro @ 2026-06-24 0:48 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: linux-mm, Vlastimil Babka, Harry Yoo, linux-fsdevel,
Linus Torvalds, Christian Brauner, Jan Kara, Mateusz Guzik,
linux-kernel
On Tue, Jun 23, 2026 at 10:09:41AM +0200, Vlastimil Babka (SUSE) wrote:
> But the argument for doing the static duration support is that it should be
> faster, not just "not slower"? So is runtime_const equivalent or for some
> fundamental reason it's slower than plain &?
Yes, on any 64bit RISC. And if nothing else, arm64 has enough users to care
about. runtime_const for _shifts_ tends to be nice and easy; for pointers...
not really.
Compiler does *not* build the address of global variable in a sequence of
shifts and bitwise operations when it needs to pass it to a function.
runtime_const_ptr() must be able to handle an arbitrary address; it can't
avoid doing the general "build a 64bit value in register", which tends to
be nasty on RISC.
If you want real ugliness, take a look at riscv - AFAICS, they wanted to
avoid a long dependency chain, so they load chunks of constant into 4 registers,
then shift and combine those. arm64 doesn't bother; IIRC, the hardware does
recognize this sequence, but I wouldn't swear on that.
> Or is the advantage that static caches can support modules and runtime_const
> can't?
Probably, but I'm not ready to give examples at the moment. There definitely
used to be __getname() users in modules, but that stopped using names_cache.
^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2026-06-24 0:48 UTC | newest]
Thread overview: 52+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-10 4:02 [RFC PATCH 00/15] kmem_cache instances with static storage duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 01/15] static kmem_cache instances for core caches Al Viro
2026-01-10 5:40 ` Matthew Wilcox
2026-01-10 6:23 ` Al Viro
2026-01-14 7:30 ` Harry Yoo
2026-01-14 7:38 ` Al Viro
2026-01-15 16:59 ` Vlastimil Babka
2026-06-11 17:13 ` Al Viro
2026-06-11 17:14 ` [PATCH v2 0/9] kmem_cache instances with static storage duration Al Viro
2026-06-11 17:14 ` [PATCH v2 1/9] static kmem_cache instances for core caches Al Viro
2026-06-11 17:14 ` [PATCH v2 2/9] allow static-duration kmem_cache in modules Al Viro
2026-06-11 17:14 ` [PATCH v2 3/9] VFS caches: switch from runtime_const() machinery to slab-static.h Al Viro
2026-06-11 17:14 ` [PATCH v2 4/9] make inode_cache statically allocated Al Viro
2026-06-11 17:14 ` [PATCH v2 5/9] make mnt_cache " Al Viro
2026-06-11 17:14 ` [PATCH v2 6/9] make bh_cachep " Al Viro
2026-06-11 17:14 ` [PATCH v2 7/9] make seq_file_cache " Al Viro
2026-06-11 17:14 ` [PATCH v2 8/9] make thread component caches (fs_cachep, files_cachep, etc.) " Al Viro
2026-06-11 17:14 ` [PATCH v2 9/9] make ufs_inode_cache " Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 01/10] static kmem_cache instances for core caches: infrastructure Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 02/10] static kmem_cache instances for core caches: setup primitives Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 03/10] allow preallocated kmem_cache instances in modules Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 04/10] VFS caches: switch from runtime_const() machinery to slab-static.h Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 05/10] make inode_cache statically allocated Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 06/10] make mnt_cache " Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 07/10] make bh_cachep " Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 08/10] make seq_file_cache " Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 09/10] make thread component caches (fs_cachep, files_cachep, etc.) " Al Viro
2026-06-13 5:09 ` [RFC PATCH v3 10/10] make ufs_inode_cache " Al Viro
2026-06-23 8:09 ` [RFC PATCH v3 00/10] kmem_cache instances with static storage duration Vlastimil Babka (SUSE)
2026-06-24 0:48 ` Al Viro
2026-01-10 4:02 ` [RFC PATCH 02/15] allow static-duration kmem_cache in modules Al Viro
2026-01-10 4:02 ` [RFC PATCH 03/15] make mnt_cache static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 04/15] turn thread_cache static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 05/15] turn signal_cache static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 06/15] turn bh_cachep static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 07/15] turn dentry_cache static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 08/15] turn files_cachep static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 09/15] make filp and bfilp caches static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 10/15] turn sighand_cache static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 11/15] turn mm_cachep static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 12/15] turn task_struct_cachep static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 13/15] turn fs_cachep static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 14/15] turn inode_cachep static-duration Al Viro
2026-01-10 4:02 ` [RFC PATCH 15/15] turn ufs_inode_cache static-duration Al Viro
2026-01-10 5:33 ` [RFC PATCH 00/15] kmem_cache instances with static storage duration Linus Torvalds
2026-01-10 6:16 ` Al Viro
2026-01-14 7:12 ` Harry Yoo
2026-01-15 0:46 ` Christoph Lameter (Ampere)
2026-01-15 2:08 ` Al Viro
2026-01-15 19:10 ` Christoph Lameter (Ampere)
2026-01-15 19:44 ` Al Viro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox