Re: [PATCH v5 7/8] mm/slab: introduce kfree_rcu_nolock()

[email protected] Wed, 29 Jul 2026 08:41:33 +0000
Newsgroups dev.linux.lists.linux-rt-devel,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 3 potential issue(=
s) to consider:
- [High] `kfree_rcu_nolock()` and `kvfree_call_rcu()` invoke `__kfree_rcu_s=
heaf()`, which acquires a `local_trylock()`. This triggers lockdep 'Invalid=
 wait context' warnings and can cause deadlocks on PREEMPT_RT.
- [Medium] Missing `kasan_record_aux_stack()` in the `fallback` path of `kf=
ree_call_rcu_nolock()` loses the original free stack trace.
- [Low] Missing struct pointer cast in the `kfree_rcu_nolock()` macro cause=
s incompatible pointer type compilation errors when `CONFIG_KVFREE_RCU_BATC=
HED` is enabled.
--

--- Patch [7]: [PATCH v5 7/8] mm/slab: introduce kfree_rcu_nolock() ---
commit 34c7828edcaca9e66aa219ee881130dc05e9102d
Author: Harry Yoo (Oracle) <[email protected]>
Subject: mm/slab: introduce kfree_rcu_nolock()

The commit introduces kfree_rcu_nolock() to handle freeing objects in unkno=
wn
contexts without deferred processing when possible. It relies on
__kfree_rcu_sheaf() for the fast path and falls back to defer_kfree_rcu()
which uses an irq_work.

> diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
> --- a/include/linux/rcupdate.h
> +++ b/include/linux/rcupdate.h
> @@ -1124,6 +1125,27 @@ do {								\
>  		kvfree_call_rcu(NULL, (void *) (___p));		\
>  } while (0)
> =20
> +/**
> + * kfree_rcu_nolock() - a version of kfree_rcu() that can be called in a=
ny context.
> + * @ptr: pointer to kfree for double-argument invocations.
> + * @kvrhf: the name of the struct kvfree_rcu_head within the type of @pt=
r.
> + *
> + * With KVFREE_RCU_BATCHED, kfree_rcu_nolock() tries hard to free objects
> + * without any deferred processing, but may still defer freeing.
> + * Large kmalloc and vmalloc objects are always deferred.
> + *
> + * kfree_rcu_nolock() supports 2-arg variant only.
> + */
> +#define kfree_rcu_nolock(ptr, kvrhf)						\
> +do {										\
> +	typeof (ptr) ___p =3D (ptr);						\
> +										\
> +	if (___p) {								\
> +		BUILD_BUG_ON(offsetof(typeof(*(ptr)), kvrhf) >=3D 4096);		\
> +		kfree_call_rcu_nolock(&((___p)->kvrhf), (void *) (___p));	\

[Severity: Low]
Is a cast to (struct kvfree_rcu_head *) needed here?=20

Because the caller typically embeds struct rcu_head, passing the member
address directly to kfree_call_rcu_nolock() results in an incompatible poin=
ter
type compilation error when CONFIG_KVFREE_RCU_BATCHED is enabled.

> diff --git a/mm/slab_common.c b/mm/slab_common.c
> --- a/mm/slab_common.c
> +++ b/mm/slab_common.c
> @@ -1296,6 +1296,33 @@ EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc);
>  EXPORT_TRACEPOINT_SYMBOL(kfree);
>  EXPORT_TRACEPOINT_SYMBOL(kmem_cache_free);
> =20
> +void kfree_call_rcu_nolock(struct kvfree_rcu_head *head, void *ptr)
> +{
> +	struct slab *slab;
> +
> +	if (!IS_ENABLED(CONFIG_KVFREE_RCU_BATCHED))
> +		goto fallback;
> +
> +	if (unlikely(is_vmalloc_addr(ptr)))
> +		goto fallback;
> +
> +	slab =3D virt_to_slab(ptr);
> +	if (unlikely(!slab))
> +		goto fallback;
> +
> +	if (unlikely(IS_ENABLED(CONFIG_NUMA) && slab_nid(slab) !=3D numa_mem_id=
()))
> +		goto fallback;
> +
> +	if (unlikely(!__kfree_rcu_sheaf(slab->slab_cache, ptr, SLAB_FREE_NOLOCK=
)))

[Severity: High]
Could calling __kfree_rcu_sheaf() here violate the unknown context
requirement?

When kfree_rcu_nolock() or kvfree_call_rcu() are called in a hardirq or NMI
context, the fastpath unconditionally executes local_trylock() inside
__kfree_rcu_sheaf():

mm/slub.c:__kfree_rcu_sheaf() {
    ...
	if (!local_trylock(&s->cpu_sheaves->lock))
		goto fail;
    ...
}

Because a local_lock on PREEMPT_RT is a sleeping lock, acquiring it under
a raw spinlock triggers lockdep "Invalid wait context" warnings, and if
called from NMI context on PREEMPT_RT, it can unconditionally deadlock.

> +		goto fallback;
> +
> +	return;
> +
> +fallback:
> +	defer_kfree_rcu(head);

[Severity: Medium]
Will this lose the original free stack trace if KASAN is enabled?

When the fastpath fails and execution jumps to fallback, the object is defe=
rred
to an irq_work without calling kasan_record_aux_stack(). Later, when
kvfree_call_rcu() is finally invoked in the irq_work context, it will
record the worker's stack trace instead of the original caller that
requested the free, making KASAN Use-After-Free reports harder to debug.

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260729-kfree_rcu_=
[email protected]?part=3D7