From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794269056; b=UrkUHt/fBEJKqWYNxeAn6g4Kzr8l6VxzZJ6os0+/XdPgnuCbZA2GK0jlxrfcAP7R6jAs zneBPaEYfXfMgRDuLkZyTUJvv9ye6+1DxZ+1jjox5jq0Lm1S6M9NbhZnXftS1cdcMqVFk juiEHSJQWpI3jsiWioeUsHSsi5B5O7x9cARtLeT3SNmz6LQb/7VOq3B4lomEpWOS7Zb5T yQ+oidyNYLY+UYkD1K7tbG31nX/1/OgjLJNycYv4ru+ksD7/YTy8+QUAp4SYn/PNW+MEc Kgpo41vdsqZvW03N7YjixVVjyQ2aQqQaa/lnh2JhE7eLLk9iAGpxEjSI6DRUbu8Fp8g== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794269056; h=Received:DKIM-Signature:Date:To:From:Subject:Message-Id; bh=fqQwualGEp5X/tGOCi/HaXQzrAh2/5lnaKsV3+VJDsI=; b=EpqeNnNOCIEYrHvuL4SmjX59yI/ql9o/5pjvseQpDTfns/Zqt2E1idTNSJofTtWL3t37 Y9cstN90q0gQCDoFdmsnyk4QswoEfEMGjQ7fELb2zQB6EXS/E7Zemg+cwJc4nq3+O3AM4 gFrsy810VGqZpl0VwYHyoVY4lxl1zdjL99H2N/U2U4FxPdRJnaxMMkjdxL3WAjYIHprNj vCFmASXrQulnKtmduoVbWde/sts4jj+gOPkoB9ggXW7xkvY+GKdgTAMVl+Qqq0cg97+hl cPOKGa/dUryymnaq5GJ4ezAU9LTHnqkK2Yh0S79n34uGbpLThAuqVQi98qCcx1R9Idg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=ETeDJbNa; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B323E606A330 for ; Tue, 10 Nov 2026 00:04:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=ETeDJbNa Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5899F1F0089F; Tue, 10 Nov 2026 00:04:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux-foundation.org; s=korg; t=1794269055; bh=fqQwualGEp5X/tGOCi/HaXQzrAh2/5lnaKsV3+VJDsI=; h=Date:To:From:Subject; b=ETeDJbNa0tApSB8oxSlWLBJaq7lNxv+98OnLoJ/Z7h/Jjp/8i7QCi0bDHVHM8Gwty IBp/YN68fsrNp2B+Cxv+8LLU/87b2yTe4UQQHAyWnyAcB7zV1Kk/3rHtxTg6ZOj3AG OeJPAmUcn1SMxEofZRiafWNbVBpInxXl0C/lXpog= Date: Mon, 09 Nov 2026 16:04:14 -0800 To: mm-commits@vger.kernel.org,terrelln@fb.com,raemoar63@gmail.com, dsterba@suse.com,david@davidgow.net,brendan.higgins@linux.dev, amit.patole@gmail.com,akpm@linux-foundation.org From: Andrew Morton Subject: + lib-tests-add-kunit-tests-for-xxhash.patch added to mm-nonmm-unstable branch Message-Id: <20261110000415.5899F1F0089F@smtp.kernel.org> X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list The patch titled Subject: lib/tests: add KUnit tests for xxHash has been added to the -mm mm-nonmm-unstable branch. Its filename is lib-tests-add-kunit-tests-for-xxhash.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/lib-tests-add-kunit-tests-for-xxhash.patch This patch will later appear in the mm-nonmm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via various branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there most days ------------------------------------------------------ From: Amit Patole Subject: lib/tests: add KUnit tests for xxHash Date: Fri, 06 Nov 2026 09:02:11 -0500 lib/xxhash.c provides xxh32() and xxh64(), used by zstd (frame checksums and long-distance matching), btrfs and erofs, where the values end up on disk. The crypto self-tests cover xxh64() through the "xxhash64" shash, but nothing tests xxh32() or the library interface directly. Add a KUnit suite with known answers from the reference xxHash implementation. The input is generated the same way as in xxHash's own sanity check, so the lengths 1, 14 and 222 reproduce the values published there. It covers: - xxh32() with two seeds and xxh64() with three, for lengths around the 4, 8, 16 and 32 byte boundaries of the algorithms; - the xxh64 streaming interface, split into two updates at every possible point and fed one byte at a time, and repeated xxh64_digest() calls; - xxh64_update() rejecting a NULL input with -EINVAL; - input at every offset from 1 to 7 bytes, which must not change the result. An AI coding assistant (Claude Opus 5.5) was used to draft the tests, and the expected values were generated with the reference implementation (python-xxhash 3.7.0) after checking it against the published sanity values. The tests were run with "tools/testing/kunit/kunit.py run" on UML (146/146 pass), built with W=1 without warnings, and checked against off-by-one changes to the length checks in xxh32(), xxh64() and xxh64_update(), which the suite catches. Link: https://lore.kernel.org/20261106-kunit-xxhash-v1-1-7b79cb6a8998@gmail.com Signed-off-by: Amit Patole Signed-off-by: Andrew Morton Cc: Nick Terrell Cc: David Sterba Cc: Brendan Higgins Cc: David Gow Cc: Rae Moar --- lib/Kconfig.debug | 14 + lib/tests/Makefile | 1 lib/tests/xxhash_kunit.c | 260 +++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) --- a/lib/Kconfig.debug~lib-tests-add-kunit-tests-for-xxhash +++ a/lib/Kconfig.debug @@ -3493,6 +3493,20 @@ config RATELIMIT_KUNIT_TEST If unsure, say N. +config XXHASH_KUNIT_TEST + tristate "KUnit test for xxHash" if !KUNIT_ALL_TESTS + depends on KUNIT + select XXHASH + default KUNIT_ALL_TESTS + help + This option enables the KUnit test suite for lib/xxhash.c, the + xxh32() and xxh64() hashes used by zstd, btrfs and erofs. The + tests check known answers from the reference xxHash + implementation, the xxh64 streaming interface and unaligned + input. + + If unsure, say N. + config UUID_KUNIT_TEST tristate "KUnit test for UUID" if !KUNIT_ALL_TESTS depends on KUNIT --- a/lib/tests/Makefile~lib-tests-add-kunit-tests-for-xxhash +++ a/lib/tests/Makefile @@ -61,5 +61,6 @@ obj-$(CONFIG_USERCOPY_KUNIT_TEST) += use obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o obj-$(CONFIG_UUID_KUNIT_TEST) += uuid_kunit.o +obj-$(CONFIG_XXHASH_KUNIT_TEST) += xxhash_kunit.o obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/ diff --git a/lib/tests/xxhash_kunit.c a/lib/tests/xxhash_kunit.c new file mode 100644 --- /dev/null +++ a/lib/tests/xxhash_kunit.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for the xxHash implementation in lib/xxhash.c + * + * The expected values come from the reference xxHash implementation. The + * input is generated the same way as in xxHash's own sanity check, so the + * entries for lengths 1, 14 and 222 match the values published there. + */ + +#include +#include +#include +#include + +#define XXH_TEST_LEN 222 + +static const u32 xxh_prime32 = 2654435761U; +static const u64 xxh_prime64 = 11400714785074694797ULL; + +struct xxh32_case { + unsigned int len; + u32 seed; + u32 hash; +}; + +struct xxh64_case { + unsigned int len; + u64 seed; + u64 hash; +}; + +static const struct xxh32_case xxh32_cases[] = { + { 0, 0x00000000, 0x02cc5d05 }, + { 1, 0x00000000, 0xcf65b03e }, + { 3, 0x00000000, 0xc23884f5 }, + { 4, 0x00000000, 0xa9de7ce9 }, + { 5, 0x00000000, 0xeb1734bb }, + { 8, 0x00000000, 0xa3f6f44b }, + { 14, 0x00000000, 0x1208e7e2 }, + { 15, 0x00000000, 0x6b859e14 }, + { 16, 0x00000000, 0x93ba3759 }, + { 17, 0x00000000, 0x89fdc23e }, + { 31, 0x00000000, 0x5f40e562 }, + { 32, 0x00000000, 0xd89829ec }, + { 33, 0x00000000, 0x31a427e5 }, + { 63, 0x00000000, 0xf1d48fdb }, + { 64, 0x00000000, 0x02e95dbb }, + { 65, 0x00000000, 0x16992b3d }, + { 100, 0x00000000, 0x96ad8143 }, + { 222, 0x00000000, 0x5bd11dbd }, + { 0, 0x9e3779b1, 0x36b78ae7 }, + { 1, 0x9e3779b1, 0xb4545aa4 }, + { 3, 0x9e3779b1, 0x1a269947 }, + { 4, 0x9e3779b1, 0x2baafe83 }, + { 5, 0x9e3779b1, 0x5874dab0 }, + { 8, 0x9e3779b1, 0xc2a8e239 }, + { 14, 0x9e3779b1, 0x6af1d1fe }, + { 15, 0x9e3779b1, 0xad53090d }, + { 16, 0x9e3779b1, 0xa94fc1e1 }, + { 17, 0x9e3779b1, 0xc9910739 }, + { 31, 0x9e3779b1, 0x5c0c3350 }, + { 32, 0x9e3779b1, 0xa5c44467 }, + { 33, 0x9e3779b1, 0x0de5b1f9 }, + { 63, 0x9e3779b1, 0x956b3d77 }, + { 64, 0x9e3779b1, 0xcf82f830 }, + { 65, 0x9e3779b1, 0x428eec5f }, + { 100, 0x9e3779b1, 0x83d48124 }, + { 222, 0x9e3779b1, 0x58803c5f }, +}; + +static const struct xxh64_case xxh64_cases[] = { + { 0, 0x0000000000000000ULL, 0xef46db3751d8e999ULL }, + { 1, 0x0000000000000000ULL, 0xe934a84adb052768ULL }, + { 3, 0x0000000000000000ULL, 0xff7e1959cb50794aULL }, + { 4, 0x0000000000000000ULL, 0x9136a0dca57457eeULL }, + { 5, 0x0000000000000000ULL, 0x9b046fb1397f09a5ULL }, + { 8, 0x0000000000000000ULL, 0xcdbcf538e71d1348ULL }, + { 14, 0x0000000000000000ULL, 0x8282dcc4994e35c8ULL }, + { 15, 0x0000000000000000ULL, 0x180719316d622d84ULL }, + { 16, 0x0000000000000000ULL, 0x98c90b57fdfcb55cULL }, + { 17, 0x0000000000000000ULL, 0x0d39a2d051a30c2cULL }, + { 31, 0x0000000000000000ULL, 0x299b39a290e6d783ULL }, + { 32, 0x0000000000000000ULL, 0x18b216492bb44b70ULL }, + { 33, 0x0000000000000000ULL, 0x55c8dc3e578f5b59ULL }, + { 63, 0x0000000000000000ULL, 0xa9efbe0fa0f3f4e7ULL }, + { 64, 0x0000000000000000ULL, 0xef558f8acac2b5cdULL }, + { 65, 0x0000000000000000ULL, 0xde0f20dc2631af7aULL }, + { 100, 0x0000000000000000ULL, 0x4bfe019cd91d9ea4ULL }, + { 222, 0x0000000000000000ULL, 0xb641ae8cb691c174ULL }, + { 0, 0x000000009e3779b1ULL, 0xac75fda2929b17efULL }, + { 1, 0x000000009e3779b1ULL, 0x5014607643a9b4c3ULL }, + { 3, 0x000000009e3779b1ULL, 0xaa8584e83660f7d1ULL }, + { 4, 0x000000009e3779b1ULL, 0xcaab286bd8e9fdb5ULL }, + { 5, 0x000000009e3779b1ULL, 0x2af5249930f984ecULL }, + { 8, 0x000000009e3779b1ULL, 0xfe0c047a5353cdacULL }, + { 14, 0x000000009e3779b1ULL, 0xc3bd6bf63deb6df0ULL }, + { 15, 0x000000009e3779b1ULL, 0xd61105c20e91f99fULL }, + { 16, 0x000000009e3779b1ULL, 0xc900ad2d536b607eULL }, + { 17, 0x000000009e3779b1ULL, 0x495cd68a647c7a22ULL }, + { 31, 0x000000009e3779b1ULL, 0xda673d5feb5c1d79ULL }, + { 32, 0x000000009e3779b1ULL, 0xb3f33bdf93ade409ULL }, + { 33, 0x000000009e3779b1ULL, 0xe92c292f64bc3071ULL }, + { 63, 0x000000009e3779b1ULL, 0x6c911fadb05b6fc2ULL }, + { 64, 0x000000009e3779b1ULL, 0xb5eeba99264cc44fULL }, + { 65, 0x000000009e3779b1ULL, 0xd3f6ff3941e310caULL }, + { 100, 0x000000009e3779b1ULL, 0x4853706dc9625caeULL }, + { 222, 0x000000009e3779b1ULL, 0x20cb8ab7ae10c14aULL }, + { 0, 0x9e3779b97f4a7c15ULL, 0xc4349fc93c010000ULL }, + { 1, 0x9e3779b97f4a7c15ULL, 0x126bb57a12364aa5ULL }, + { 3, 0x9e3779b97f4a7c15ULL, 0xe23f055f9113033dULL }, + { 4, 0x9e3779b97f4a7c15ULL, 0xf6337e5fb526b92eULL }, + { 5, 0x9e3779b97f4a7c15ULL, 0x3fe27fb9d0eb8e4cULL }, + { 8, 0x9e3779b97f4a7c15ULL, 0x4fe88e05b3a5bfd8ULL }, + { 14, 0x9e3779b97f4a7c15ULL, 0xbdd0f167d252e0bbULL }, + { 15, 0x9e3779b97f4a7c15ULL, 0xb0298e00622d8613ULL }, + { 16, 0x9e3779b97f4a7c15ULL, 0xb37a43269a32566aULL }, + { 17, 0x9e3779b97f4a7c15ULL, 0xfd7e04ed256c9413ULL }, + { 31, 0x9e3779b97f4a7c15ULL, 0xb9fa34ecbf9b57ffULL }, + { 32, 0x9e3779b97f4a7c15ULL, 0xe65ea5f4eff5d5deULL }, + { 33, 0x9e3779b97f4a7c15ULL, 0xf166a3272cadc4abULL }, + { 63, 0x9e3779b97f4a7c15ULL, 0x0a36d884436efe01ULL }, + { 64, 0x9e3779b97f4a7c15ULL, 0xe7bd5052c0d2145eULL }, + { 65, 0x9e3779b97f4a7c15ULL, 0xfea9a8f0561339ddULL }, + { 100, 0x9e3779b97f4a7c15ULL, 0x8dd80a6ef6296bf7ULL }, + { 222, 0x9e3779b97f4a7c15ULL, 0x8cdf13ba7f241d67ULL }, +}; + +static u8 *xxh_test_buf(struct kunit *test) +{ + u64 gen = xxh_prime32; + u8 *buf; + int i; + + buf = kunit_kmalloc(test, XXH_TEST_LEN, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, buf); + + for (i = 0; i < XXH_TEST_LEN; i++) { + buf[i] = gen >> 56; + gen *= xxh_prime64; + } + return buf; +} + +static void xxh32_case_desc(const struct xxh32_case *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "len %u seed %#x", + t->len, t->seed); +} + +static void xxh64_case_desc(const struct xxh64_case *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "len %u seed %#llx", + t->len, t->seed); +} + +KUNIT_ARRAY_PARAM(xxh32, xxh32_cases, xxh32_case_desc); +KUNIT_ARRAY_PARAM(xxh64, xxh64_cases, xxh64_case_desc); + +static void xxh32_test(struct kunit *test) +{ + const struct xxh32_case *t = test->param_value; + u8 *buf = xxh_test_buf(test); + + KUNIT_EXPECT_EQ(test, xxh32(buf, t->len, t->seed), t->hash); +} + +static void xxh64_test(struct kunit *test) +{ + const struct xxh64_case *t = test->param_value; + u8 *buf = xxh_test_buf(test); + + KUNIT_EXPECT_EQ(test, xxh64(buf, t->len, t->seed), t->hash); +} + +/* + * The streaming interface must give the same result as xxh64() however the + * input is split. Try every split into two updates, and one byte at a time. + */ +static void xxh64_streaming_test(struct kunit *test) +{ + const struct xxh64_case *t = test->param_value; + u8 *buf = xxh_test_buf(test); + struct xxh64_state state; + unsigned int split, i; + + for (split = 0; split <= t->len; split++) { + xxh64_reset(&state, t->seed); + KUNIT_ASSERT_EQ(test, xxh64_update(&state, buf, split), 0); + KUNIT_ASSERT_EQ(test, xxh64_update(&state, buf + split, + t->len - split), 0); + KUNIT_EXPECT_EQ_MSG(test, xxh64_digest(&state), t->hash, + "split at %u", split); + } + + xxh64_reset(&state, t->seed); + for (i = 0; i < t->len; i++) + KUNIT_ASSERT_EQ(test, xxh64_update(&state, buf + i, 1), 0); + KUNIT_EXPECT_EQ(test, xxh64_digest(&state), t->hash); + + /* xxh64_digest() does not change the state, so it can be repeated. */ + KUNIT_EXPECT_EQ(test, xxh64_digest(&state), t->hash); +} + +static void xxh64_update_null_test(struct kunit *test) +{ + struct xxh64_state state; + + xxh64_reset(&state, 0); + KUNIT_EXPECT_EQ(test, xxh64_update(&state, NULL, 0), -EINVAL); + /* A rejected update leaves the state as it was. */ + KUNIT_EXPECT_EQ(test, xxh64_digest(&state), xxh64(NULL, 0, 0)); +} + +/* The result does not depend on the alignment of the input. */ +static void xxh_unaligned_test(struct kunit *test) +{ + u8 *buf = xxh_test_buf(test); + u32 h32 = xxh32(buf, XXH_TEST_LEN, 0); + u64 h64 = xxh64(buf, XXH_TEST_LEN, 0); + u8 *copy; + int off; + + copy = kunit_kmalloc(test, XXH_TEST_LEN + 8, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, copy); + + for (off = 1; off < 8; off++) { + struct xxh64_state state; + + memcpy(copy + off, buf, XXH_TEST_LEN); + KUNIT_EXPECT_EQ_MSG(test, xxh32(copy + off, XXH_TEST_LEN, 0), + h32, "offset %d", off); + KUNIT_EXPECT_EQ_MSG(test, xxh64(copy + off, XXH_TEST_LEN, 0), + h64, "offset %d", off); + + xxh64_reset(&state, 0); + xxh64_update(&state, copy + off, 5); + xxh64_update(&state, copy + off + 5, XXH_TEST_LEN - 5); + KUNIT_EXPECT_EQ_MSG(test, xxh64_digest(&state), h64, + "offset %d", off); + } +} + +static struct kunit_case xxhash_test_cases[] = { + KUNIT_CASE_PARAM(xxh32_test, xxh32_gen_params), + KUNIT_CASE_PARAM(xxh64_test, xxh64_gen_params), + KUNIT_CASE_PARAM(xxh64_streaming_test, xxh64_gen_params), + KUNIT_CASE(xxh64_update_null_test), + KUNIT_CASE(xxh_unaligned_test), + {} +}; + +static struct kunit_suite xxhash_test_suite = { + .name = "xxhash", + .test_cases = xxhash_test_cases, +}; + +kunit_test_suite(xxhash_test_suite); + +MODULE_DESCRIPTION("KUnit tests for xxHash"); +MODULE_LICENSE("GPL"); _ Patches currently in -mm which might be from amit.patole@gmail.com are lib-genalloc-dont-dereference-a-null-pool-in-gen_pool_dma_alloc.patch lib-tests-add-kunit-tests-for-genalloc.patch lib-tests-add-kunit-tests-for-xxhash.patch