* [PATCH V1 0/2] slub_kunit: add a test case for {kmalloc,kfree}_nolock
@ 2026-03-30 12:05 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 12:05 ` [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock Harry Yoo (Oracle)
0 siblings, 2 replies; 8+ messages in thread
From: Harry Yoo (Oracle) @ 2026-03-30 12:05 UTC (permalink / raw)
To: Vlastimil Babka, Andrew Morton
Cc: Hao Li, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-kernel, linux-mm, Harry Yoo (Oracle)
This came up while developing kvfree_rcu_nolock(), but even without that
it's worth adding a test case. Let's add it in advance.
Probably a similar test case for the page allocator is worth adding
but I'm not sure where the right place would be.
While at it, also add the missing MAINTAINERS entry for slub_kunit.c.
Harry Yoo (Oracle) (2):
MAINTAINERS: add lib/tests/slub_kunit.c to SLAB ALLOCATOR section
lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
MAINTAINERS | 1 +
lib/tests/slub_kunit.c | 88 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
base-commit: dbc785fb4d9cfa0115e69e614fe20b4ab90f8366
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH V1 1/2] MAINTAINERS: add lib/tests/slub_kunit.c to SLAB ALLOCATOR section
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 ` 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)
1 sibling, 1 reply; 8+ messages in thread
From: Harry Yoo (Oracle) @ 2026-03-30 12:05 UTC (permalink / raw)
To: Vlastimil Babka, Andrew Morton
Cc: Hao Li, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-kernel, linux-mm, Harry Yoo (Oracle)
The slub_kunit module has been maintained by SLAB ALLOCATOR folks,
but is missing in the MAINTAINERS file. Add the missing entry.
Signed-off-by: Harry Yoo (Oracle) <harry@kernel.org>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 96ea84948d76..5f5add4f72a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24354,6 +24354,7 @@ F: Documentation/admin-guide/mm/slab.rst
F: Documentation/mm/slab.rst
F: include/linux/mempool.h
F: include/linux/slab.h
+F: lib/tests/slub_kunit.c
F: mm/failslab.c
F: mm/mempool.c
F: mm/slab.h
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
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 12:05 ` Harry Yoo (Oracle)
2026-03-30 16:49 ` David Rientjes
` (2 more replies)
1 sibling, 3 replies; 8+ messages in thread
From: Harry Yoo (Oracle) @ 2026-03-30 12:05 UTC (permalink / raw)
To: Vlastimil Babka, Andrew Morton
Cc: Hao Li, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-kernel, linux-mm, Harry Yoo (Oracle)
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>
---
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),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH V1 1/2] MAINTAINERS: add lib/tests/slub_kunit.c to SLAB ALLOCATOR section
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
0 siblings, 0 replies; 8+ messages in thread
From: David Rientjes @ 2026-03-30 16:48 UTC (permalink / raw)
To: Harry Yoo (Oracle)
Cc: Vlastimil Babka, Andrew Morton, Hao Li, Christoph Lameter,
Roman Gushchin, linux-kernel, linux-mm
On Mon, 30 Mar 2026, Harry Yoo (Oracle) wrote:
> The slub_kunit module has been maintained by SLAB ALLOCATOR folks,
> but is missing in the MAINTAINERS file. Add the missing entry.
>
> Signed-off-by: Harry Yoo (Oracle) <harry@kernel.org>
Acked-by: David Rientjes <rientjes@google.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
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)
2 siblings, 0 replies; 8+ messages in thread
From: David Rientjes @ 2026-03-30 16:49 UTC (permalink / raw)
To: Harry Yoo (Oracle)
Cc: Vlastimil Babka, Andrew Morton, Hao Li, Christoph Lameter,
Roman Gushchin, linux-kernel, linux-mm
On Mon, 30 Mar 2026, 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>
Acked-by: David Rientjes <rientjes@google.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
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)
2 siblings, 0 replies; 8+ messages in thread
From: Harry Yoo (Oracle) @ 2026-03-31 3:04 UTC (permalink / raw)
To: Vlastimil Babka, Andrew Morton
Cc: Hao Li, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-kernel, linux-mm
On Mon, Mar 30, 2026 at 09:05:16PM +0900, 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>
> ---
> 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
> +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;
One thing sashiko pointed out [1]: '0' as gfp for kmalloc() is
unnecessarily restrictive. (it's not kmalloc_nolock()!), it should be:
`gfp_t gfp = (i % 2) ? GFP_KERNEL : GFP_KERNEL_ACCOUNT;`
[1] https://sashiko.dev/#/patchset/20260330120517.104743-1-harry%40kernel.org
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
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)
2026-04-03 10:01 ` Harry Yoo (Oracle)
2 siblings, 1 reply; 8+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-04-02 14:36 UTC (permalink / raw)
To: Harry Yoo (Oracle), Andrew Morton
Cc: Hao Li, Christoph Lameter, David Rientjes, Roman Gushchin,
linux-kernel, linux-mm, Alexei Starovoitov
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),
> {}
> };
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH V1 2/2] lib/tests/slub_kunit: add a test case for {kmalloc,kfree}_nolock
2026-04-02 14:36 ` Vlastimil Babka (SUSE)
@ 2026-04-03 10:01 ` Harry Yoo (Oracle)
0 siblings, 0 replies; 8+ messages in thread
From: Harry Yoo (Oracle) @ 2026-04-03 10:01 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Andrew Morton, Hao Li, Christoph Lameter, David Rientjes,
Roman Gushchin, linux-kernel, linux-mm, Alexei Starovoitov
On Thu, Apr 02, 2026 at 04:36:59PM +0200, Vlastimil Babka (SUSE) wrote:
> 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,
Thanks for catching that!
> there's not even some "return -EINVAL" skeleton
> otherwise, AFAICS.
Right.
> Didn't check the various other definitions, but guess
> we'll need to put some/all of this behind #ifdef's then?
I'll make sure it builds w/o CONFIG_PERF_EVENTS and send v2.
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-04-03 10:01 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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)
2026-04-03 10:01 ` Harry Yoo (Oracle)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox