From: "Vlastimil Babka (SUSE)" <vbabka@kernel.org>
To: "Harry Yoo (Oracle)" <harry@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>
Cc: Hao Li <hao.li@linux.dev>, Christoph Lameter <cl@gentwo.org>,
David Rientjes <rientjes@google.com>,
Roman Gushchin <roman.gushchin@linux.dev>,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
Alexei Starovoitov <ast@kernel.org>
Subject: Re: [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
Date: Thu, 2 Apr 2026 16:36:59 +0200 [thread overview]
Message-ID: <26e81ffe-08ad-4c3f-a360-d45c3cb32ee2@kernel.org> (raw)
In-Reply-To: <20260330120517.104743-3-harry@kernel.org>
On 3/30/26 2:05 PM, Harry Yoo (Oracle) wrote:
> Testing invocation of {kmalloc,kfree}_nolock() during kmalloc() or
> kfree() is tricky, and it is even harder to ensure that slowpaths are
> properly tested. Lack of such testing has led to late discovery of
> the bug fixed by commit a1e244a9f177 ("mm/slab: use prandom if
> !allow_spin").
>
> Add a slub_kunit test that allocates and frees objects in a tight loop
> while a perf event triggers NMIs on the same task, invoking
> {kmalloc,kfree}_nolock() from the NMI handler.
>
> Signed-off-by: Harry Yoo (Oracle) <harry@kernel.org>
perf_event_create_kernel_counter() seems to only exist with
CONFIG_PERF_EVENTS, there's not even some "return -EINVAL" skeleton
otherwise, AFAICS. Didn't check the various other definitions, but guess
we'll need to put some/all of this behind #ifdef's then?
> ---
> lib/tests/slub_kunit.c | 88 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
>
> diff --git a/lib/tests/slub_kunit.c b/lib/tests/slub_kunit.c
> index 848b682a2d70..2ed5f90a748a 100644
> --- a/lib/tests/slub_kunit.c
> +++ b/lib/tests/slub_kunit.c
> @@ -7,6 +7,7 @@
> #include <linux/kernel.h>
> #include <linux/rcupdate.h>
> #include <linux/delay.h>
> +#include <linux/perf_event.h>
> #include "../mm/slab.h"
>
> static struct kunit_resource resource;
> @@ -291,6 +292,92 @@ static void test_krealloc_redzone_zeroing(struct kunit *test)
> kmem_cache_destroy(s);
> }
>
> +#define REPEAT_TIMES 1000
> +#define LOOP_SIZE 1000
> +static void *objects[LOOP_SIZE];
> +
> +struct nmi_context {
> + struct kunit *test;
> + int callback_count;
> + int alloc_ok;
> + int alloc_fail;
> + struct perf_event *event;
> +};
> +
> +static struct perf_event_attr nmi_hw_attr = {
> + .type = PERF_TYPE_HARDWARE,
> + .config = PERF_COUNT_HW_CPU_CYCLES,
> + .size = sizeof(struct perf_event_attr),
> + .pinned = 1,
> + .disabled = 1,
> + .freq = 1,
> + .sample_freq = 100000,
> +};
> +
> +static void kmalloc_kfree_nolock_in_nmi(struct perf_event *event,
> + struct perf_sample_data *data,
> + struct pt_regs *regs)
> +{
> + void *objp;
> + gfp_t gfp;
> + struct nmi_context *ctx = event->overflow_handler_context;
> +
> + /* __GFP_ACCOUNT to test kmalloc_nolock() in alloc_slab_obj_exts() */
> + gfp = (ctx->callback_count % 2) ? 0 : __GFP_ACCOUNT;
> + objp = kmalloc_nolock(64, gfp, NUMA_NO_NODE);
> +
> + if (objp)
> + ctx->alloc_ok++;
> + else
> + ctx->alloc_fail++;
> +
> + kfree_nolock(objp);
> + ctx->callback_count++;
> +}
> +
> +static void test_kmalloc_kfree_nolock(struct kunit *test)
> +{
> + int i, j;
> + struct nmi_context ctx = { .test = test };
> + struct perf_event *event;
> + bool alloc_fail = false;
> +
> + event = perf_event_create_kernel_counter(&nmi_hw_attr, -1, current,
> + kmalloc_kfree_nolock_in_nmi,
> + &ctx);
> + if (IS_ERR(event))
> + kunit_skip(test, "Failed to create perf event");
> + ctx.event = event;
> + perf_event_enable(ctx.event);
> + for (i = 0; i < REPEAT_TIMES; i++) {
> + for (j = 0; j < LOOP_SIZE; j++) {
> + gfp_t gfp = (i % 2) ? 0 : __GFP_ACCOUNT;
> +
> + objects[j] = kmalloc(64, gfp);
> + if (!objects[j]) {
> + j--;
> + while (j >= 0)
> + kfree(objects[j--]);
> + alloc_fail = true;
> + goto cleanup;
> + }
> + }
> + for (j = 0; j < LOOP_SIZE; j++)
> + kfree(objects[j]);
> + }
> +
> +cleanup:
> + perf_event_disable(ctx.event);
> + perf_event_release_kernel(ctx.event);
> +
> + kunit_info(test, "callback_count: %d, alloc_ok: %d, alloc_fail: %d\n",
> + ctx.callback_count, ctx.alloc_ok, ctx.alloc_fail);
> +
> + if (alloc_fail)
> + kunit_skip(test, "Allocation failed");
> + KUNIT_EXPECT_EQ(test, 0, slab_errors);
> +}
> +
> static int test_init(struct kunit *test)
> {
> slab_errors = 0;
> @@ -315,6 +402,7 @@ static struct kunit_case test_cases[] = {
> KUNIT_CASE(test_kfree_rcu_wq_destroy),
> KUNIT_CASE(test_leak_destroy),
> KUNIT_CASE(test_krealloc_redzone_zeroing),
> + KUNIT_CASE_SLOW(test_kmalloc_kfree_nolock),
> {}
> };
>
next prev parent reply other threads:[~2026-04-02 14:37 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-30 12:05 [PATCH V1 0/2] slub_kunit: add a test case for {kmalloc,kfree}_nolock Harry Yoo (Oracle)
2026-03-30 12:05 ` [PATCH V1 1/2] MAINTAINERS: add lib/tests/slub_kunit.c to SLAB ALLOCATOR section Harry Yoo (Oracle)
2026-03-30 16:48 ` David Rientjes
2026-03-30 12:05 ` [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock Harry Yoo (Oracle)
2026-03-30 16:49 ` David Rientjes
2026-03-31 3:04 ` Harry Yoo (Oracle)
2026-04-02 14:36 ` Vlastimil Babka (SUSE) [this message]
2026-04-03 10:01 ` Harry Yoo (Oracle)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=26e81ffe-08ad-4c3f-a360-d45c3cb32ee2@kernel.org \
--to=vbabka@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=ast@kernel.org \
--cc=cl@gentwo.org \
--cc=hao.li@linux.dev \
--cc=harry@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=rientjes@google.com \
--cc=roman.gushchin@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox