Skip to content

Commit a1e244a

Browse files
hygonitehcaster
authored andcommitted
mm/slab: use prandom if !allow_spin
When CONFIG_SLAB_FREELIST_RANDOM is enabled and get_random_u32() is called in an NMI context, lockdep complains because it acquires a local_lock: ================================ WARNING: inconsistent lock state 6.19.0-rc5-slab-for-next+ #325 Tainted: G N -------------------------------- inconsistent {INITIAL USE} -> {IN-NMI} usage. kunit_try_catch/8312 [HC2[2]:SC0[0]:HE0:SE1] takes: ffff88a02ec49cc0 (batched_entropy_u32.lock){-.-.}-{3:3}, at: get_random_u32+0x7f/0x2e0 {INITIAL USE} state was registered at: lock_acquire+0xd9/0x2f0 get_random_u32+0x93/0x2e0 __get_random_u32_below+0x17/0x70 cache_random_seq_create+0x121/0x1c0 init_cache_random_seq+0x5d/0x110 do_kmem_cache_create+0x1e0/0xa30 __kmem_cache_create_args+0x4ec/0x830 create_kmalloc_caches+0xe6/0x130 kmem_cache_init+0x1b1/0x660 mm_core_init+0x1d8/0x4b0 start_kernel+0x620/0xcd0 x86_64_start_reservations+0x18/0x30 x86_64_start_kernel+0xf3/0x140 common_startup_64+0x13e/0x148 irq event stamp: 76 hardirqs last enabled at (75): [<ffffffff8298b77a>] exc_nmi+0x11a/0x240 hardirqs last disabled at (76): [<ffffffff8298b991>] sysvec_irq_work+0x11/0x110 softirqs last enabled at (0): [<ffffffff813b2dda>] copy_process+0xc7a/0x2350 softirqs last disabled at (0): [<0000000000000000>] 0x0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(batched_entropy_u32.lock); <Interrupt> lock(batched_entropy_u32.lock); *** DEADLOCK *** Fix this by using pseudo-random number generator if !allow_spin. This means kmalloc_nolock() users won't get truly random numbers, but there is not much we can do about it. Note that an NMI handler might interrupt prandom_u32_state() and change the random state, but that's safe. Link: https://lore.kernel.org/all/0c33bdee-6de8-4d9f-92ca-4f72c1b6fb9f@suse.cz Fixes: af92793 ("slab: Introduce kmalloc_nolock() and kfree_nolock().") Cc: stable@vger.kernel.org Signed-off-by: Harry Yoo <harry.yoo@oracle.com> Link: https://patch.msgid.link/20260210081900.329447-3-harry.yoo@oracle.com Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
1 parent 144080a commit a1e244a

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

mm/slub.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <linux/prefetch.h>
4444
#include <linux/memcontrol.h>
4545
#include <linux/random.h>
46+
#include <linux/prandom.h>
4647
#include <kunit/test.h>
4748
#include <kunit/test-bug.h>
4849
#include <linux/sort.h>
@@ -3311,8 +3312,11 @@ static void *next_freelist_entry(struct kmem_cache *s,
33113312
return (char *)start + idx;
33123313
}
33133314

3315+
static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
3316+
33143317
/* Shuffle the single linked freelist based on a random pre-computed sequence */
3315-
static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
3318+
static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab,
3319+
bool allow_spin)
33163320
{
33173321
void *start;
33183322
void *cur;
@@ -3323,7 +3327,19 @@ static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
33233327
return false;
33243328

33253329
freelist_count = oo_objects(s->oo);
3326-
pos = get_random_u32_below(freelist_count);
3330+
if (allow_spin) {
3331+
pos = get_random_u32_below(freelist_count);
3332+
} else {
3333+
struct rnd_state *state;
3334+
3335+
/*
3336+
* An interrupt or NMI handler might interrupt and change
3337+
* the state in the middle, but that's safe.
3338+
*/
3339+
state = &get_cpu_var(slab_rnd_state);
3340+
pos = prandom_u32_state(state) % freelist_count;
3341+
put_cpu_var(slab_rnd_state);
3342+
}
33273343

33283344
page_limit = slab->objects * s->size;
33293345
start = fixup_red_left(s, slab_address(slab));
@@ -3350,7 +3366,8 @@ static inline int init_cache_random_seq(struct kmem_cache *s)
33503366
return 0;
33513367
}
33523368
static inline void init_freelist_randomization(void) { }
3353-
static inline bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
3369+
static inline bool shuffle_freelist(struct kmem_cache *s, struct slab *slab,
3370+
bool allow_spin)
33543371
{
33553372
return false;
33563373
}
@@ -3441,7 +3458,7 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
34413458
alloc_slab_obj_exts_early(s, slab);
34423459
account_slab(slab, oo_order(oo), s, flags);
34433460

3444-
shuffle = shuffle_freelist(s, slab);
3461+
shuffle = shuffle_freelist(s, slab, allow_spin);
34453462

34463463
if (!shuffle) {
34473464
start = fixup_red_left(s, start);
@@ -8341,6 +8358,9 @@ void __init kmem_cache_init_late(void)
83418358
{
83428359
flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM, 0);
83438360
WARN_ON(!flushwq);
8361+
#ifdef CONFIG_SLAB_FREELIST_RANDOM
8362+
prandom_init_once(&slab_rnd_state);
8363+
#endif
83448364
}
83458365

83468366
int do_kmem_cache_create(struct kmem_cache *s, const char *name,

0 commit comments

Comments
 (0)