Extract a private header and convert the prime_numbers self-test to a
KUnit test. I considered parameterizing the test using
`KUNIT_CASE_PARAM` but didn't see how it was possible since the test
logic is entangled with the test parameter generation logic.
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
lib/Kconfig.debug | 14 +++++
lib/math/prime_numbers.c | 87 +++++-----------------------
lib/math/prime_numbers_private.h | 17 ++++++
lib/math/tests/Makefile | 1 +
lib/math/tests/prime_numbers_kunit.c | 59 +++++++++++++++++++
tools/testing/selftests/lib/config | 1 -
tools/testing/selftests/lib/prime_numbers.sh | 4 --
7 files changed, 106 insertions(+), 77 deletions(-)
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0ccfab3ecd21..7570caaacddb 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -3210,6 +3210,20 @@ config GCD_KUNIT_TEST
If unsure, say N
+config PRIME_NUMBERS_KUNIT_TEST
+ tristate "Prime number generator test" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ select PRIME_NUMBERS
+ default KUNIT_ALL_TESTS
+ help
+ This option enables the KUnit test suite for the {is,next}_prime_number
+ functions.
+
+ Enabling this option will include tests that compare the prime number
+ generator functions against a brute force implementation.
+
+ If unsure, say N
+
endif # RUNTIME_TESTING_MENU
config ARCH_USE_MEMTEST
diff --git a/lib/math/prime_numbers.c b/lib/math/prime_numbers.c
index 9a17ee9af93a..f88d6e64dbdc 100644
--- a/lib/math/prime_numbers.c
+++ b/lib/math/prime_numbers.c
@@ -1,16 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
-#define pr_fmt(fmt) "prime numbers: " fmt
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/prime_numbers.h>
#include <linux/slab.h>
-struct primes {
- struct rcu_head rcu;
- unsigned long last, sz;
- unsigned long primes[];
-};
+#include "prime_numbers_private.h"
#if BITS_PER_LONG == 64
static const struct primes small_primes = {
@@ -62,9 +57,21 @@ static const struct primes small_primes = {
static DEFINE_MUTEX(lock);
static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes);
-static unsigned long selftest_max;
+#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST)
+void with_primes(void *ctx, primes_fn fn)
+{
+ rcu_read_lock();
+ fn(ctx, rcu_dereference(primes));
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(with_primes);
+
+EXPORT_SYMBOL(slow_is_prime_number);
-static bool slow_is_prime_number(unsigned long x)
+#else
+static
+#endif
+bool slow_is_prime_number(unsigned long x)
{
unsigned long y = int_sqrt(x);
@@ -239,77 +246,13 @@ bool is_prime_number(unsigned long x)
}
EXPORT_SYMBOL(is_prime_number);
-static void dump_primes(void)
-{
- const struct primes *p;
- char *buf;
-
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-
- rcu_read_lock();
- p = rcu_dereference(primes);
-
- if (buf)
- bitmap_print_to_pagebuf(true, buf, p->primes, p->sz);
- pr_info("primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s\n",
- p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf);
-
- rcu_read_unlock();
-
- kfree(buf);
-}
-
-static int selftest(unsigned long max)
-{
- unsigned long x, last;
-
- if (!max)
- return 0;
-
- for (last = 0, x = 2; x < max; x++) {
- bool slow = slow_is_prime_number(x);
- bool fast = is_prime_number(x);
-
- if (slow != fast) {
- pr_err("inconsistent result for is-prime(%lu): slow=%s, fast=%s!\n",
- x, slow ? "yes" : "no", fast ? "yes" : "no");
- goto err;
- }
-
- if (!slow)
- continue;
-
- if (next_prime_number(last) != x) {
- pr_err("incorrect result for next-prime(%lu): expected %lu, got %lu\n",
- last, x, next_prime_number(last));
- goto err;
- }
- last = x;
- }
-
- pr_info("%s(%lu) passed, last prime was %lu\n", __func__, x, last);
- return 0;
-
-err:
- dump_primes();
- return -EINVAL;
-}
-
-static int __init primes_init(void)
-{
- return selftest(selftest_max);
-}
-
static void __exit primes_exit(void)
{
free_primes();
}
-module_init(primes_init);
module_exit(primes_exit);
-module_param_named(selftest, selftest_max, ulong, 0400);
-
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Prime number library");
MODULE_LICENSE("GPL");
diff --git a/lib/math/prime_numbers_private.h b/lib/math/prime_numbers_private.h
new file mode 100644
index 000000000000..a4cab3c8c727
--- /dev/null
+++ b/lib/math/prime_numbers_private.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/types.h>
+
+struct primes {
+ struct rcu_head rcu;
+ unsigned long last, sz;
+ unsigned long primes[];
+};
+
+#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST)
+bool slow_is_prime_number(unsigned long x);
+typedef void (*primes_fn)(void *, const struct primes *);
+
+// Calls the callback under RCU lock. The callback must not retain the primes pointer.
+void with_primes(void *ctx, primes_fn fn);
+#endif
diff --git a/lib/math/tests/Makefile b/lib/math/tests/Makefile
index 6a04b4eb22b6..40ad9de29acc 100644
--- a/lib/math/tests/Makefile
+++ b/lib/math/tests/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_INT_POW_TEST) += int_pow_kunit.o
obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += int_sqrt_kunit.o
obj-$(CONFIG_GCD_KUNIT_TEST) += gcd_kunit.o
+obj-$(CONFIG_PRIME_NUMBERS_KUNIT_TEST) += prime_numbers_kunit.o
diff --git a/lib/math/tests/prime_numbers_kunit.c b/lib/math/tests/prime_numbers_kunit.c
new file mode 100644
index 000000000000..2f1643208c66
--- /dev/null
+++ b/lib/math/tests/prime_numbers_kunit.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <kunit/test.h>
+#include <linux/module.h>
+#include <linux/prime_numbers.h>
+
+#include "../prime_numbers_private.h"
+
+static void dump_primes(void *ctx, const struct primes *p)
+{
+ static char buf[PAGE_SIZE];
+ struct kunit_suite *suite = ctx;
+
+ bitmap_print_to_pagebuf(true, buf, p->primes, p->sz);
+ kunit_info(suite, "primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s",
+ p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf);
+}
+
+static void prime_numbers_test(struct kunit *test)
+{
+ const unsigned long max = 65536;
+ unsigned long x, last, next;
+
+ for (last = 0, x = 2; x < max; x++) {
+ const bool slow = slow_is_prime_number(x);
+ const bool fast = is_prime_number(x);
+
+ KUNIT_ASSERT_EQ_MSG(test, slow, fast, "is-prime(%lu)", x);
+
+ if (!slow)
+ continue;
+
+ next = next_prime_number(last);
+ KUNIT_ASSERT_EQ_MSG(test, next, x, "next-prime(%lu)", last);
+ last = next;
+ }
+}
+
+static void kunit_suite_exit(struct kunit_suite *suite)
+{
+ with_primes(suite, dump_primes);
+}
+
+static struct kunit_case prime_numbers_cases[] = {
+ KUNIT_CASE(prime_numbers_test),
+ {},
+};
+
+static struct kunit_suite prime_numbers_suite = {
+ .name = "math-prime_numbers",
+ .suite_exit = kunit_suite_exit,
+ .test_cases = prime_numbers_cases,
+};
+
+kunit_test_suite(prime_numbers_suite);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Prime number library");
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/lib/config b/tools/testing/selftests/lib/config
index dc15aba8d0a3..306a3d4dca98 100644
--- a/tools/testing/selftests/lib/config
+++ b/tools/testing/selftests/lib/config
@@ -1,5 +1,4 @@
CONFIG_TEST_PRINTF=m
CONFIG_TEST_SCANF=m
CONFIG_TEST_BITMAP=m
-CONFIG_PRIME_NUMBERS=m
CONFIG_TEST_BITOPS=m
diff --git a/tools/testing/selftests/lib/prime_numbers.sh b/tools/testing/selftests/lib/prime_numbers.sh
deleted file mode 100755
index 370b79a9cb2e..000000000000
--- a/tools/testing/selftests/lib/prime_numbers.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Checks fast/slow prime_number generation for inconsistencies
-$(dirname $0)/../kselftest/module.sh "prime numbers" prime_numbers selftest=65536
--
2.48.1
On Sat, Feb 08, 2025 at 09:44:39PM -0500, Tamir Duberstein wrote: > Extract a private header and convert the prime_numbers self-test to a > KUnit test. I considered parameterizing the test using > `KUNIT_CASE_PARAM` but didn't see how it was possible since the test > logic is entangled with the test parameter generation logic. > > Signed-off-by: Tamir Duberstein <tamird@gmail.com> > --- > lib/Kconfig.debug | 14 +++++ > lib/math/prime_numbers.c | 87 +++++----------------------- > lib/math/prime_numbers_private.h | 17 ++++++ > lib/math/tests/Makefile | 1 + > lib/math/tests/prime_numbers_kunit.c | 59 +++++++++++++++++++ > tools/testing/selftests/lib/config | 1 - > tools/testing/selftests/lib/prime_numbers.sh | 4 -- > 7 files changed, 106 insertions(+), 77 deletions(-) Thanks! I've applied this and rebased it onto: https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=for-next/move-kunit-tests -- Kees Cook
On Mon, Feb 10, 2025 at 9:37 PM Kees Cook <kees@kernel.org> wrote: > > On Sat, Feb 08, 2025 at 09:44:39PM -0500, Tamir Duberstein wrote: > > Extract a private header and convert the prime_numbers self-test to a > > KUnit test. I considered parameterizing the test using > > `KUNIT_CASE_PARAM` but didn't see how it was possible since the test > > logic is entangled with the test parameter generation logic. > > > > Signed-off-by: Tamir Duberstein <tamird@gmail.com> > > --- > > lib/Kconfig.debug | 14 +++++ > > lib/math/prime_numbers.c | 87 +++++----------------------- > > lib/math/prime_numbers_private.h | 17 ++++++ > > lib/math/tests/Makefile | 1 + > > lib/math/tests/prime_numbers_kunit.c | 59 +++++++++++++++++++ > > tools/testing/selftests/lib/config | 1 - > > tools/testing/selftests/lib/prime_numbers.sh | 4 -- > > 7 files changed, 106 insertions(+), 77 deletions(-) > > Thanks! I've applied this and rebased it onto: > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=for-next/move-kunit-tests > > -- > Kees Cook Thanks! Could you also take the first patch in the series[0]? The new test won't build without it because lib/math/tests/Makefile is dead code. [0] https://lore.kernel.org/all/20250208-prime_numbers-kunit-convert-v5-1-b0cb82ae7c7d@gmail.com/ Cheers. Tamir
Ah, I see https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=for-next/move-kunit-tests&id=3e50ba8fc834cadead733e4feeb969fce2f3b6e1 now. On Mon, Feb 10, 2025 at 9:47 PM Tamir Duberstein <tamird@gmail.com> wrote: > > On Mon, Feb 10, 2025 at 9:37 PM Kees Cook <kees@kernel.org> wrote: > > > > On Sat, Feb 08, 2025 at 09:44:39PM -0500, Tamir Duberstein wrote: > > > Extract a private header and convert the prime_numbers self-test to a > > > KUnit test. I considered parameterizing the test using > > > `KUNIT_CASE_PARAM` but didn't see how it was possible since the test > > > logic is entangled with the test parameter generation logic. > > > > > > Signed-off-by: Tamir Duberstein <tamird@gmail.com> > > > --- > > > lib/Kconfig.debug | 14 +++++ > > > lib/math/prime_numbers.c | 87 +++++----------------------- > > > lib/math/prime_numbers_private.h | 17 ++++++ > > > lib/math/tests/Makefile | 1 + > > > lib/math/tests/prime_numbers_kunit.c | 59 +++++++++++++++++++ > > > tools/testing/selftests/lib/config | 1 - > > > tools/testing/selftests/lib/prime_numbers.sh | 4 -- > > > 7 files changed, 106 insertions(+), 77 deletions(-) > > > > Thanks! I've applied this and rebased it onto: > > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=for-next/move-kunit-tests > > > > -- > > Kees Cook > > Thanks! Could you also take the first patch in the series[0]? The new > test won't build without it because lib/math/tests/Makefile is dead > code. > > [0] https://lore.kernel.org/all/20250208-prime_numbers-kunit-convert-v5-1-b0cb82ae7c7d@gmail.com/ > > Cheers. > Tamir
Kees, it looks like the private header didn't make it to your tree.
This bit is missing:
diff --git a/lib/math/prime_numbers.c b/lib/math/prime_numbers.c
index f88d6e64dbdc..de59f001c8c7 100644
--- a/lib/math/prime_numbers.c
+++ b/lib/math/prime_numbers.c
@@ -58,6 +58,7 @@ static DEFINE_MUTEX(lock);
static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes);
#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST)
+// Calls the callback under RCU lock. The callback must not retain
the primes pointer.
void with_primes(void *ctx, primes_fn fn)
{
rcu_read_lock();
diff --git a/lib/math/prime_numbers_private.h b/lib/math/prime_numbers_private.h
new file mode 100644
index 000000000000..f3ebf5386e6b
--- /dev/null
+++ b/lib/math/prime_numbers_private.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/types.h>
+
+struct primes {
+ struct rcu_head rcu;
+ unsigned long last, sz;
+ unsigned long primes[];
+};
+
+#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST)
+typedef void (*primes_fn)(void *, const struct primes *);
+
+void with_primes(void *ctx, primes_fn fn);
+bool slow_is_prime_number(unsigned long x);
+#endif
Tamir
On Mon, Feb 10, 2025 at 9:52 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> Ah, I see https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=for-next/move-kunit-tests&id=3e50ba8fc834cadead733e4feeb969fce2f3b6e1
> now.
>
> On Mon, Feb 10, 2025 at 9:47 PM Tamir Duberstein <tamird@gmail.com> wrote:
> >
> > On Mon, Feb 10, 2025 at 9:37 PM Kees Cook <kees@kernel.org> wrote:
> > >
> > > On Sat, Feb 08, 2025 at 09:44:39PM -0500, Tamir Duberstein wrote:
> > > > Extract a private header and convert the prime_numbers self-test to a
> > > > KUnit test. I considered parameterizing the test using
> > > > `KUNIT_CASE_PARAM` but didn't see how it was possible since the test
> > > > logic is entangled with the test parameter generation logic.
> > > >
> > > > Signed-off-by: Tamir Duberstein <tamird@gmail.com>
> > > > ---
> > > > lib/Kconfig.debug | 14 +++++
> > > > lib/math/prime_numbers.c | 87 +++++-----------------------
> > > > lib/math/prime_numbers_private.h | 17 ++++++
> > > > lib/math/tests/Makefile | 1 +
> > > > lib/math/tests/prime_numbers_kunit.c | 59 +++++++++++++++++++
> > > > tools/testing/selftests/lib/config | 1 -
> > > > tools/testing/selftests/lib/prime_numbers.sh | 4 --
> > > > 7 files changed, 106 insertions(+), 77 deletions(-)
> > >
> > > Thanks! I've applied this and rebased it onto:
> > > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=for-next/move-kunit-tests
> > >
> > > --
> > > Kees Cook
> >
> > Thanks! Could you also take the first patch in the series[0]? The new
> > test won't build without it because lib/math/tests/Makefile is dead
> > code.
> >
> > [0] https://lore.kernel.org/all/20250208-prime_numbers-kunit-convert-v5-1-b0cb82ae7c7d@gmail.com/
> >
> > Cheers.
> > Tamir
On Tue, Feb 11, 2025 at 06:51:09AM -0500, Tamir Duberstein wrote: > Kees, it looks like the private header didn't make it to your tree. > This bit is missing: Whoops! Thanks. I've added it (and fixed the comment style). I really need to do my build/run testing from a fresh checkout instead of in the same work tree. :( -- Kees Cook
On Tue, Feb 11, 2025 at 11:38 AM Kees Cook <kees@kernel.org> wrote: > > On Tue, Feb 11, 2025 at 06:51:09AM -0500, Tamir Duberstein wrote: > > Kees, it looks like the private header didn't make it to your tree. > > This bit is missing: > > Whoops! Thanks. I've added it (and fixed the comment style). > > I really need to do my build/run testing from a fresh checkout instead > of in the same work tree. :( > > -- > Kees Cook Thanks! I think it's customary to have comments only in the sources - I see you also included it in the header.
© 2016 - 2025 Red Hat, Inc.