Skip to content

Commit a13b68d

Browse files
hygonitehcaster
authored andcommitted
mm/slab: allow specifying free pointer offset when using constructor
When a slab cache has a constructor, the free pointer is placed after the object because certain fields must not be overwritten even after the object is freed. However, some fields that the constructor does not initialize can safely be overwritten after free. Allow specifying the free pointer offset within the object, reducing the overall object size when some fields can be reused for the free pointer. Adjust the document accordingly. Signed-off-by: Harry Yoo <harry.yoo@oracle.com> Link: https://patch.msgid.link/20260113061845.159790-3-harry.yoo@oracle.com Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
1 parent b85f369 commit a13b68d

3 files changed

Lines changed: 21 additions & 17 deletions

File tree

include/linux/slab.h

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -299,24 +299,26 @@ struct kmem_cache_args {
299299
unsigned int usersize;
300300
/**
301301
* @freeptr_offset: Custom offset for the free pointer
302-
* in &SLAB_TYPESAFE_BY_RCU caches
302+
* in caches with &SLAB_TYPESAFE_BY_RCU or @ctor
303303
*
304-
* By default &SLAB_TYPESAFE_BY_RCU caches place the free pointer
305-
* outside of the object. This might cause the object to grow in size.
306-
* Cache creators that have a reason to avoid this can specify a custom
307-
* free pointer offset in their struct where the free pointer will be
308-
* placed.
304+
* By default, &SLAB_TYPESAFE_BY_RCU and @ctor caches place the free
305+
* pointer outside of the object. This might cause the object to grow
306+
* in size. Cache creators that have a reason to avoid this can specify
307+
* a custom free pointer offset in their data structure where the free
308+
* pointer will be placed.
309309
*
310-
* Note that placing the free pointer inside the object requires the
311-
* caller to ensure that no fields are invalidated that are required to
312-
* guard against object recycling (See &SLAB_TYPESAFE_BY_RCU for
313-
* details).
310+
* For caches with &SLAB_TYPESAFE_BY_RCU, the caller must ensure that
311+
* the free pointer does not overlay fields required to guard against
312+
* object recycling (See &SLAB_TYPESAFE_BY_RCU for details).
314313
*
315-
* Using %0 as a value for @freeptr_offset is valid. If @freeptr_offset
316-
* is specified, %use_freeptr_offset must be set %true.
314+
* For caches with @ctor, the caller must ensure that the free pointer
315+
* does not overlay fields initialized by the constructor.
316+
*
317+
* Currently, only caches with &SLAB_TYPESAFE_BY_RCU or @ctor
318+
* may specify @freeptr_offset.
317319
*
318-
* Note that @ctor currently isn't supported with custom free pointers
319-
* as a @ctor requires an external free pointer.
320+
* Using %0 as a value for @freeptr_offset is valid. If @freeptr_offset
321+
* is specified, @use_freeptr_offset must be set %true.
320322
*/
321323
unsigned int freeptr_offset;
322324
/**

mm/slab_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static struct kmem_cache *create_cache(const char *name,
239239
err = -EINVAL;
240240
if (args->use_freeptr_offset &&
241241
(args->freeptr_offset >= object_size ||
242-
!(flags & SLAB_TYPESAFE_BY_RCU) ||
242+
(!(flags & SLAB_TYPESAFE_BY_RCU) && !args->ctor) ||
243243
!IS_ALIGNED(args->freeptr_offset, __alignof__(freeptr_t))))
244244
goto out;
245245

mm/slub.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7998,7 +7998,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
79987998
s->inuse = size;
79997999

80008000
if (((flags & SLAB_TYPESAFE_BY_RCU) && !args->use_freeptr_offset) ||
8001-
(flags & SLAB_POISON) || s->ctor ||
8001+
(flags & SLAB_POISON) ||
8002+
(s->ctor && !args->use_freeptr_offset) ||
80028003
((flags & SLAB_RED_ZONE) &&
80038004
(s->object_size < sizeof(void *) || slub_debug_orig_size(s)))) {
80048005
/*
@@ -8019,7 +8020,8 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
80198020
*/
80208021
s->offset = size;
80218022
size += sizeof(void *);
8022-
} else if ((flags & SLAB_TYPESAFE_BY_RCU) && args->use_freeptr_offset) {
8023+
} else if (((flags & SLAB_TYPESAFE_BY_RCU) || s->ctor) &&
8024+
args->use_freeptr_offset) {
80238025
s->offset = args->freeptr_offset;
80248026
} else {
80258027
/*

0 commit comments

Comments
 (0)