From: Christoph Hellwig <hch@lst.de>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Richard Henderson <richard.henderson@linaro.org>,
Matt Turner <mattst88@gmail.com>,
Magnus Lindholm <linmag7@gmail.com>,
Russell King <linux@armlinux.org.uk>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Huacai Chen <chenhuacai@kernel.org>,
WANG Xuerui <kernel@xen0n.name>,
Madhavan Srinivasan <maddy@linux.ibm.com>,
Michael Ellerman <mpe@ellerman.id.au>,
Nicholas Piggin <npiggin@gmail.com>,
"Christophe Leroy (CS GROUP)" <chleroy@kernel.org>,
Paul Walmsley <pjw@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
Albert Ou <aou@eecs.berkeley.edu>,
Alexandre Ghiti <alex@ghiti.fr>,
Heiko Carstens <hca@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
Alexander Gordeev <agordeev@linux.ibm.com>,
Christian Borntraeger <borntraeger@linux.ibm.com>,
Sven Schnelle <svens@linux.ibm.com>,
"David S. Miller" <davem@davemloft.net>,
Andreas Larsson <andreas@gaisler.com>,
Richard Weinberger <richard@nod.at>,
Anton Ivanov <anton.ivanov@cambridgegreys.com>,
Johannes Berg <johannes@sipsolutions.net>,
Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Dan Williams <dan.j.williams@intel.com>, Chris Mason <clm@fb.com>,
David Sterba <dsterba@suse.com>, Arnd Bergmann <arnd@arndb.de>,
Song Liu <song@kernel.org>, Yu Kuai <yukuai@fnnas.com>,
Li Nan <linan122@huawei.com>, "Theodore Ts'o" <tytso@mit.edu>,
"Jason A. Donenfeld" <Jason@zx2c4.com>,
linux-alpha@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev,
linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
linux-s390@vger.kernel.org, sparclinux@vger.kernel.org,
linux-um@lists.infradead.org, linux-crypto@vger.kernel.org,
linux-btrfs@vger.kernel.org, linux-arch@vger.kernel.org,
linux-raid@vger.kernel.org
Subject: [PATCH 27/27] xor: add a kunit test case
Date: Wed, 11 Mar 2026 08:03:59 +0100 [thread overview]
Message-ID: <20260311070416.972667-28-hch@lst.de> (raw)
In-Reply-To: <20260311070416.972667-1-hch@lst.de>
Add a test case for the XOR routines loosely based on the CRC kunit
test.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
lib/raid/Kconfig | 11 ++
lib/raid/xor/Makefile | 2 +-
lib/raid/xor/tests/Makefile | 3 +
lib/raid/xor/tests/xor_kunit.c | 180 +++++++++++++++++++++++++++++++++
4 files changed, 195 insertions(+), 1 deletion(-)
create mode 100644 lib/raid/xor/tests/Makefile
create mode 100644 lib/raid/xor/tests/xor_kunit.c
diff --git a/lib/raid/Kconfig b/lib/raid/Kconfig
index 4359971ebd04..97c123806466 100644
--- a/lib/raid/Kconfig
+++ b/lib/raid/Kconfig
@@ -6,3 +6,14 @@ config XOR_BLOCKS
# selected by architectures that provide an optimized XOR implementation
config XOR_BLOCKS_ARCH
bool
+
+config XOR_KUNIT_TEST
+ tristate "KUnit tests for xor_gen" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ select XOR_BLOCKS
+ help
+ Unit tests for the XOR library functions.
+
+ This is intended to help people writing architecture-specific
+ optimized versions. If unsure, say N.
diff --git a/lib/raid/xor/Makefile b/lib/raid/xor/Makefile
index 7b748ddda9d4..74185bdc3dd8 100644
--- a/lib/raid/xor/Makefile
+++ b/lib/raid/xor/Makefile
@@ -30,7 +30,7 @@ xor-$(CONFIG_SPARC64) += sparc/xor-sparc64.o sparc/xor-sparc64-glue.o
xor-$(CONFIG_S390) += s390/xor.o
xor-$(CONFIG_X86_32) += x86/xor-avx.o x86/xor-sse.o x86/xor-mmx.o
xor-$(CONFIG_X86_64) += x86/xor-avx.o x86/xor-sse.o
-
+obj-y += tests/
CFLAGS_arm/xor-neon.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_arm/xor-neon.o += $(CC_FLAGS_NO_FPU)
diff --git a/lib/raid/xor/tests/Makefile b/lib/raid/xor/tests/Makefile
new file mode 100644
index 000000000000..661e8f6ffd1f
--- /dev/null
+++ b/lib/raid/xor/tests/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_XOR_KUNIT_TEST) += xor_kunit.o
diff --git a/lib/raid/xor/tests/xor_kunit.c b/lib/raid/xor/tests/xor_kunit.c
new file mode 100644
index 000000000000..23ee415e914c
--- /dev/null
+++ b/lib/raid/xor/tests/xor_kunit.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Unit test the XOR library functions.
+ *
+ * Copyright 2024 Google LLC
+ * Copyright 2026 Christoph Hellwig
+ *
+ * Based on the CRC tests by Eric Biggers <ebiggers@google.com>.
+ */
+#include <kunit/test.h>
+#include <linux/prandom.h>
+#include <linux/string_choices.h>
+#include <linux/vmalloc.h>
+#include <linux/raid/xor.h>
+
+#define XOR_KUNIT_SEED 42
+#define XOR_KUNIT_MAX_BYTES 16384
+#define XOR_KUNIT_MAX_BUFFERS 64
+#define XOR_KUNIT_NUM_TEST_ITERS 1000
+
+static struct rnd_state rng;
+static void *test_buffers[XOR_KUNIT_MAX_BUFFERS];
+static void *test_dest;
+static void *test_ref;
+static size_t test_buflen;
+
+static u32 rand32(void)
+{
+ return prandom_u32_state(&rng);
+}
+
+static u32 rand32_below(u32 ceil)
+{
+ return __limit_random_u32_below(ceil, prandom_u32_state(&rng));
+}
+
+/* Reference implementation using dumb byte-wise XOR */
+static void xor_ref(void *dest, void **srcs, unsigned int src_cnt,
+ unsigned int bytes)
+{
+ unsigned int off, idx;
+ u8 *d = dest;
+
+ for (off = 0; off < bytes; off++) {
+ for (idx = 0; idx < src_cnt; idx++) {
+ u8 *src = srcs[idx];
+
+ d[off] ^= src[off];
+ }
+ }
+}
+
+/* Generate a random length that is a multiple of 512. */
+static unsigned int generate_random_length(unsigned int max_length)
+{
+ return (rand32_below(max_length / 512) + 1) * 512;
+}
+
+/* Generate a random alignment that is a multiple of 32. */
+static unsigned int generate_random_alignment(unsigned int max_alignment)
+{
+ return (rand32_below((max_alignment + 1) / 32)) * 32;
+}
+
+static void xor_generate_random_data(void)
+{
+ int i;
+
+ prandom_bytes_state(&rng, test_dest, test_buflen);
+ memcpy(test_ref, test_dest, test_buflen);
+ for (i = 0; i < XOR_KUNIT_MAX_BUFFERS; i++)
+ prandom_bytes_state(&rng, test_buffers[i], test_buflen);
+}
+
+/* Test that xor_gen gives the same result as a reference implementation. */
+static void xor_test(struct kunit *test)
+{
+ void *aligned_buffers[XOR_KUNIT_MAX_BUFFERS];
+ size_t i;
+
+ for (i = 0; i < XOR_KUNIT_NUM_TEST_ITERS; i++) {
+ unsigned int nr_buffers =
+ rand32_below(XOR_KUNIT_MAX_BUFFERS) + 1;
+ unsigned int len = generate_random_length(XOR_KUNIT_MAX_BYTES);
+ unsigned int max_alignment, align = 0;
+ void *buffers;
+
+ if (rand32() % 8 == 0)
+ /* Refresh the data occasionally. */
+ xor_generate_random_data();
+
+ /*
+ * If we're not using the entire buffer size, inject randomize
+ * alignment into the buffer.
+ */
+ max_alignment = XOR_KUNIT_MAX_BYTES - len;
+ if (max_alignment) {
+ int j;
+
+ align = generate_random_alignment(max_alignment);
+ for (j = 0; j < nr_buffers; j++)
+ aligned_buffers[j] = test_buffers[j] +
+ generate_random_alignment(max_alignment);
+ buffers = aligned_buffers;
+ } else {
+ buffers = test_buffers;
+ }
+
+ /*
+ * Compute the XOR, and verify that it equals the XOR computed
+ * by a simple byte-at-a-time reference implementation.
+ */
+ xor_ref(test_ref + align, buffers, nr_buffers, len);
+ xor_gen(test_dest + align, buffers, nr_buffers, len);
+ KUNIT_EXPECT_MEMEQ_MSG(test, test_ref, test_dest, len,
+ "Wrong result with buffers=%u, len=%u, align=%s",
+ nr_buffers, len, str_yes_no(max_alignment));
+ }
+}
+
+static struct kunit_case xor_test_cases[] = {
+ KUNIT_CASE(xor_test),
+ {},
+};
+
+static int xor_suite_init(struct kunit_suite *suite)
+{
+ int i;
+
+ /*
+ * Allocate the test buffer using vmalloc() with a page-aligned length
+ * so that it is immediately followed by a guard page. This allows
+ * buffer overreads to be detected, even in assembly code.
+ */
+ test_buflen = round_up(XOR_KUNIT_MAX_BYTES, PAGE_SIZE);
+ test_ref = vmalloc(test_buflen);
+ if (!test_ref)
+ return -ENOMEM;
+ test_dest = vmalloc(test_buflen);
+ if (!test_dest)
+ goto out_free_ref;
+ for (i = 0; i < XOR_KUNIT_MAX_BUFFERS; i++) {
+ test_buffers[i] = vmalloc(test_buflen);
+ if (!test_buffers[i])
+ goto out_free_buffers;
+ }
+
+ prandom_seed_state(&rng, XOR_KUNIT_SEED);
+ xor_generate_random_data();
+ return 0;
+
+out_free_buffers:
+ while (--i >= 0)
+ vfree(test_buffers[i]);
+ vfree(test_dest);
+out_free_ref:
+ vfree(test_ref);
+ return -ENOMEM;
+}
+
+static void xor_suite_exit(struct kunit_suite *suite)
+{
+ int i;
+
+ vfree(test_ref);
+ vfree(test_dest);
+ for (i = 0; i < XOR_KUNIT_MAX_BUFFERS; i++)
+ vfree(test_buffers[i]);
+}
+
+static struct kunit_suite xor_test_suite = {
+ .name = "xor",
+ .test_cases = xor_test_cases,
+ .suite_init = xor_suite_init,
+ .suite_exit = xor_suite_exit,
+};
+kunit_test_suite(xor_test_suite);
+
+MODULE_DESCRIPTION("Unit tests and benchmarks for the XOR library functions");
+MODULE_LICENSE("GPL");
--
2.47.3
next prev parent reply other threads:[~2026-03-11 7:10 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-11 7:03 cleanup the RAID5 XOR library v2 Christoph Hellwig
2026-03-11 7:03 ` [PATCH 01/27] xor: assert that xor_blocks is not from preemptible user context Christoph Hellwig
2026-03-11 7:03 ` [PATCH 02/27] arm/xor: remove in_interrupt() handling Christoph Hellwig
2026-03-11 7:03 ` [PATCH 03/27] um/xor: cleanup xor.h Christoph Hellwig
2026-03-11 8:45 ` Richard Weinberger
2026-03-11 7:03 ` [PATCH 04/27] xor: move to lib/raid/ Christoph Hellwig
2026-03-11 7:03 ` [PATCH 05/27] xor: small cleanups Christoph Hellwig
2026-03-11 7:03 ` [PATCH 06/27] xor: cleanup registration and probing Christoph Hellwig
2026-03-11 7:03 ` [PATCH 07/27] xor: split xor.h Christoph Hellwig
2026-03-11 7:03 ` [PATCH 08/27] xor: remove macro abuse for XOR implementation registrations Christoph Hellwig
2026-03-11 7:03 ` [PATCH 09/27] xor: move generic implementations out of asm-generic/xor.h Christoph Hellwig
2026-03-11 7:03 ` [PATCH 10/27] alpha: move the XOR code to lib/raid/ Christoph Hellwig
2026-03-16 22:12 ` Magnus Lindholm
2026-03-11 7:03 ` [PATCH 11/27] arm: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 12/27] arm64: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 13/27] loongarch: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 14/27] powerpc: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 15/27] riscv: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 16/27] sparc: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 17/27] s390: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 18/27] x86: " Christoph Hellwig
2026-03-11 7:03 ` [PATCH 19/27] xor: avoid indirect calls for arm64-optimized ops Christoph Hellwig
2026-03-11 7:03 ` [PATCH 20/27] xor: make xor.ko self-contained in lib/raid/ Christoph Hellwig
2026-03-11 7:03 ` [PATCH 21/27] xor: add a better public API Christoph Hellwig
2026-03-11 7:03 ` [PATCH 22/27] async_xor: use xor_gen Christoph Hellwig
2026-03-11 7:03 ` [PATCH 23/27] btrfs: " Christoph Hellwig
2026-03-12 6:14 ` David Sterba
2026-03-11 7:03 ` [PATCH 24/27] xor: pass the entire operation to the low-level ops Christoph Hellwig
2026-03-11 7:03 ` [PATCH 25/27] xor: use static_call for xor_gen Christoph Hellwig
2026-03-11 7:03 ` [PATCH 26/27] random: factor out a __limit_random_u32_below helper Christoph Hellwig
2026-03-11 22:29 ` Eric Biggers
2026-03-12 8:38 ` David Laight
2026-03-12 13:46 ` Jason A. Donenfeld
2026-03-11 7:03 ` Christoph Hellwig [this message]
2026-03-12 0:54 ` [PATCH 27/27] xor: add a kunit test case Eric Biggers
2026-03-11 18:57 ` cleanup the RAID5 XOR library v2 Andrew Morton
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=20260311070416.972667-28-hch@lst.de \
--to=hch@lst.de \
--cc=Jason@zx2c4.com \
--cc=agordeev@linux.ibm.com \
--cc=akpm@linux-foundation.org \
--cc=alex@ghiti.fr \
--cc=andreas@gaisler.com \
--cc=anton.ivanov@cambridgegreys.com \
--cc=aou@eecs.berkeley.edu \
--cc=arnd@arndb.de \
--cc=borntraeger@linux.ibm.com \
--cc=bp@alien8.de \
--cc=catalin.marinas@arm.com \
--cc=chenhuacai@kernel.org \
--cc=chleroy@kernel.org \
--cc=clm@fb.com \
--cc=dan.j.williams@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=davem@davemloft.net \
--cc=dsterba@suse.com \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=herbert@gondor.apana.org.au \
--cc=hpa@zytor.com \
--cc=johannes@sipsolutions.net \
--cc=kernel@xen0n.name \
--cc=linan122@huawei.com \
--cc=linmag7@gmail.com \
--cc=linux-alpha@vger.kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-raid@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=linux-s390@vger.kernel.org \
--cc=linux-um@lists.infradead.org \
--cc=linux@armlinux.org.uk \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=loongarch@lists.linux.dev \
--cc=maddy@linux.ibm.com \
--cc=mattst88@gmail.com \
--cc=mingo@redhat.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=richard.henderson@linaro.org \
--cc=richard@nod.at \
--cc=song@kernel.org \
--cc=sparclinux@vger.kernel.org \
--cc=svens@linux.ibm.com \
--cc=tglx@kernel.org \
--cc=tytso@mit.edu \
--cc=will@kernel.org \
--cc=x86@kernel.org \
--cc=yukuai@fnnas.com \
/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