Skip to content

Commit 280ea9c

Browse files
hygonitehcaster
authored andcommitted
mm/slab: avoid allocating slabobj_ext array from its own slab
When allocating slabobj_ext array in alloc_slab_obj_exts(), the array can be allocated from the same slab we're allocating the array for. This led to obj_exts_in_slab() incorrectly returning true [1], although the array is not allocated from wasted space of the slab. Vlastimil Babka observed that this problem should be fixed even when ignoring its incompatibility with obj_exts_in_slab(), because it creates slabs that are never freed as there is always at least one allocated object. To avoid this, use the next kmalloc size or large kmalloc when the array can be allocated from the same cache we're allocating the array for. In case of random kmalloc caches, there are multiple kmalloc caches for the same size and the cache is selected based on the caller address. Because it is fragile to ensure the same caller address is passed to kmalloc_slab(), kmalloc_noprof(), and kmalloc_node_noprof(), bump the size to (s->object_size + 1) when the sizes are equal, instead of directly comparing the kmem_cache pointers. Note that this doesn't happen when memory allocation profiling is disabled, as when the allocation of the array is triggered by memory cgroup (KMALLOC_CGROUP), the array is allocated from KMALLOC_NORMAL. Reported-by: kernel test robot <oliver.sang@intel.com> Closes: https://lore.kernel.org/oe-lkp/202601231457.f7b31e09-lkp@intel.com [1] Cc: stable@vger.kernel.org Fixes: 4b87369 ("mm/slab: add allocation accounting into slab allocation and free paths") Signed-off-by: Harry Yoo <harry.yoo@oracle.com> Link: https://patch.msgid.link/20260126125714.88008-1-harry.yoo@oracle.com Reviewed-by: Hao Li <hao.li@linux.dev> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
1 parent d907bf4 commit 280ea9c

1 file changed

Lines changed: 53 additions & 7 deletions

File tree

mm/slub.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,49 @@ static inline void init_slab_obj_exts(struct slab *slab)
20922092
slab->obj_exts = 0;
20932093
}
20942094

2095+
/*
2096+
* Calculate the allocation size for slabobj_ext array.
2097+
*
2098+
* When memory allocation profiling is enabled, the obj_exts array
2099+
* could be allocated from the same slab cache it's being allocated for.
2100+
* This would prevent the slab from ever being freed because it would
2101+
* always contain at least one allocated object (its own obj_exts array).
2102+
*
2103+
* To avoid this, increase the allocation size when we detect the array
2104+
* may come from the same cache, forcing it to use a different cache.
2105+
*/
2106+
static inline size_t obj_exts_alloc_size(struct kmem_cache *s,
2107+
struct slab *slab, gfp_t gfp)
2108+
{
2109+
size_t sz = sizeof(struct slabobj_ext) * slab->objects;
2110+
struct kmem_cache *obj_exts_cache;
2111+
2112+
/*
2113+
* slabobj_ext array for KMALLOC_CGROUP allocations
2114+
* are served from KMALLOC_NORMAL caches.
2115+
*/
2116+
if (!mem_alloc_profiling_enabled())
2117+
return sz;
2118+
2119+
if (sz > KMALLOC_MAX_CACHE_SIZE)
2120+
return sz;
2121+
2122+
if (!is_kmalloc_normal(s))
2123+
return sz;
2124+
2125+
obj_exts_cache = kmalloc_slab(sz, NULL, gfp, 0);
2126+
/*
2127+
* We can't simply compare s with obj_exts_cache, because random kmalloc
2128+
* caches have multiple caches per size, selected by caller address.
2129+
* Since caller address may differ between kmalloc_slab() and actual
2130+
* allocation, bump size when sizes are equal.
2131+
*/
2132+
if (s->object_size == obj_exts_cache->object_size)
2133+
return obj_exts_cache->object_size + 1;
2134+
2135+
return sz;
2136+
}
2137+
20952138
int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
20962139
gfp_t gfp, bool new_slab)
20972140
{
@@ -2100,26 +2143,26 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
21002143
unsigned long new_exts;
21012144
unsigned long old_exts;
21022145
struct slabobj_ext *vec;
2146+
size_t sz;
21032147

21042148
gfp &= ~OBJCGS_CLEAR_MASK;
21052149
/* Prevent recursive extension vector allocation */
21062150
gfp |= __GFP_NO_OBJ_EXT;
21072151

2152+
sz = obj_exts_alloc_size(s, slab, gfp);
2153+
21082154
/*
21092155
* Note that allow_spin may be false during early boot and its
21102156
* restricted GFP_BOOT_MASK. Due to kmalloc_nolock() only supporting
21112157
* architectures with cmpxchg16b, early obj_exts will be missing for
21122158
* very early allocations on those.
21132159
*/
2114-
if (unlikely(!allow_spin)) {
2115-
size_t sz = objects * sizeof(struct slabobj_ext);
2116-
2160+
if (unlikely(!allow_spin))
21172161
vec = kmalloc_nolock(sz, __GFP_ZERO | __GFP_NO_OBJ_EXT,
21182162
slab_nid(slab));
2119-
} else {
2120-
vec = kcalloc_node(objects, sizeof(struct slabobj_ext), gfp,
2121-
slab_nid(slab));
2122-
}
2163+
else
2164+
vec = kmalloc_node(sz, gfp | __GFP_ZERO, slab_nid(slab));
2165+
21232166
if (!vec) {
21242167
/*
21252168
* Try to mark vectors which failed to allocate.
@@ -2133,6 +2176,9 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
21332176
return -ENOMEM;
21342177
}
21352178

2179+
VM_WARN_ON_ONCE(virt_to_slab(vec) != NULL &&
2180+
virt_to_slab(vec)->slab_cache == s);
2181+
21362182
new_exts = (unsigned long)vec;
21372183
if (unlikely(!allow_spin))
21382184
new_exts |= OBJEXTS_NOSPIN_ALLOC;

0 commit comments

Comments
 (0)