Re: [PATCH for-next v3 7/9] mm/slab: introduce kfree_rcu_nolock()

From: XIAO WU

Date: Mon Jun 22 2026 - 10:59:03 EST


Hi Harry,

On Mon, Jun 22, 2026 at 02:28:44PM +0900, Harry Yoo wrote:
> On 6/21/26 9:29 AM, XIAO WU wrote:
> > I was able to reproduce this in QEMU with KASAN. The trigger is as
> > simple as passing a large (>8KB) kmalloc buffer to the new function.
>
> Thanks for taking a look, but this was intentional.
>
> I should have documented that only kmalloc_nolock() ->
> kfree_rcu_nolock() is allowed and kmalloc() -> kfree_rcu_nolock()
> is not allowed (yet).
>
> Since kmalloc_nolock() does not support large kmalloc, the warning
> is not supposed to trigger. That is why I added only debug warnings.

Thank you very much for taking the time to explain — I really
appreciate it, especially since I'm still learning my way around the
mm/ subsystem. You are absolutely right that kmalloc_nolock() returns
NULL for sizes above KMALLOC_MAX_CACHE_SIZE, so a proper caller using
the kmalloc_nolock() → kfree_rcu_nolock() pairing would never hit this.

I did notice one small thing that I wanted to gently bring up, though.
Please forgive me if I'm missing something obvious here.

When I was reading through the surrounding code to understand the
pattern better, I noticed that kfree_nolock() — which has the same
"only for kmalloc_nolock()" constraint (documented in the comment at
mm/slub.c:6828-6835) — actually does check for a NULL slab:

void kfree_nolock(const void *object)
{
...
slab = virt_to_slab(object);
if (unlikely(!slab)) {
WARN_ONCE(1, "large_kmalloc is not supported by kfree_nolock()");
return;
}
s = slab->slab_cache;
...

So kfree_nolock() gracefully returns with a warning even though it too
expects only kmalloc_nolock() callers. That pattern seemed really
sensible to me — it costs almost nothing and prevents a panic if
someone ever passes the wrong pointer (which they shouldn't, but as you
mentioned, the constraint isn't documented on kfree_call_rcu_nolock()
yet).

I also wondered about the difference between WARN_ONCE (used in
kfree_nolock) and VM_WARN_ON_ONCE (used in kfree_call_rcu_nolock). If
I understand correctly, VM_WARN_ON_ONCE compiles away entirely on
production kernels without CONFIG_DEBUG_VM, which would make the
subsequent NULL dereference completely silent — no warning, just a
panic. That seems a bit scary for something that's exported to
modules via EXPORT_SYMBOL_GPL.

And since you mentioned that kmalloc() → kfree_rcu_nolock() support is
planned for the future (the "yet") — wouldn't this code path need the
NULL check at that point anyway?

I was thinking something like this would make the function consistent
with kfree_nolock() and also make it forward-compatible with the
planned kmalloc() support:

--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -1266,10 +1266,16 @@ void kfree_call_rcu_nolock(struct rcu_head *head, void *ptr)
{
struct slab *slab;
struct kmem_cache *s;

- VM_WARN_ON_ONCE(is_vmalloc_addr(ptr) || !virt_to_slab(ptr));
-
slab = virt_to_slab(ptr);
+ /*
+ * kmalloc_nolock() never produces large-kmalloc or vmalloc
+ * addresses, but be defensive: fall back to defer_kfree_rcu()
+ * for unsupported pointer types, consistent with kfree_nolock().
+ */
+ if (unlikely(!slab))
+ goto fallback;
+
s = slab->slab_cache;

if (__kfree_rcu_sheaf(s, ptr, /* allow_spin = */ false))
return;

+fallback:
defer_kfree_rcu(head);
}

Of course, this is just a suggestion — you know this code far better
than I do. If you feel the current code is fine as-is with proper
documentation, I completely understand and won't press the point
further.

Either way, thank you again for the explanation, and for working on
this series — having kfree_rcu_nolock() available for BPF and other
contexts will be really valuable.

Thanks,
XIAO