18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Test cases for <linux/hash.h> and <linux/stringhash.h> 48c2ecf20Sopenharmony_ci * This just verifies that various ways of computing a hash 58c2ecf20Sopenharmony_ci * produce the same thing and, for cases where a k-bit hash 68c2ecf20Sopenharmony_ci * value is requested, is of the requested size. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * We fill a buffer with a 255-byte null-terminated string, 98c2ecf20Sopenharmony_ci * and use both full_name_hash() and hashlen_string() to hash the 108c2ecf20Sopenharmony_ci * substrings from i to j, where 0 <= i < j < 256. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The returned values are used to check that __hash_32() and 138c2ecf20Sopenharmony_ci * __hash_32_generic() compute the same thing. Likewise hash_32() 148c2ecf20Sopenharmony_ci * and hash_64(). 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt "\n" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/compiler.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/hash.h> 238c2ecf20Sopenharmony_ci#include <linux/stringhash.h> 248c2ecf20Sopenharmony_ci#include <linux/printk.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 32-bit XORSHIFT generator. Seed must not be zero. */ 278c2ecf20Sopenharmony_cistatic u32 __init __attribute_const__ 288c2ecf20Sopenharmony_cixorshift(u32 seed) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci seed ^= seed << 13; 318c2ecf20Sopenharmony_ci seed ^= seed >> 17; 328c2ecf20Sopenharmony_ci seed ^= seed << 5; 338c2ecf20Sopenharmony_ci return seed; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Given a non-zero x, returns a non-zero byte. */ 378c2ecf20Sopenharmony_cistatic u8 __init __attribute_const__ 388c2ecf20Sopenharmony_cimod255(u32 x) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci x = (x & 0xffff) + (x >> 16); /* 1 <= x <= 0x1fffe */ 418c2ecf20Sopenharmony_ci x = (x & 0xff) + (x >> 8); /* 1 <= x <= 0x2fd */ 428c2ecf20Sopenharmony_ci x = (x & 0xff) + (x >> 8); /* 1 <= x <= 0x100 */ 438c2ecf20Sopenharmony_ci x = (x & 0xff) + (x >> 8); /* 1 <= x <= 0xff */ 448c2ecf20Sopenharmony_ci return x; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Fill the buffer with non-zero bytes. */ 488c2ecf20Sopenharmony_cistatic void __init 498c2ecf20Sopenharmony_cifill_buf(char *buf, size_t len, u32 seed) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci size_t i; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 548c2ecf20Sopenharmony_ci seed = xorshift(seed); 558c2ecf20Sopenharmony_ci buf[i] = mod255(seed); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci * Test the various integer hash functions. h64 (or its low-order bits) 618c2ecf20Sopenharmony_ci * is the integer to hash. hash_or accumulates the OR of the hash values, 628c2ecf20Sopenharmony_ci * which are later checked to see that they cover all the requested bits. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * Because these functions (as opposed to the string hashes) are all 658c2ecf20Sopenharmony_ci * inline, the code being tested is actually in the module, and you can 668c2ecf20Sopenharmony_ci * recompile and re-test the module without rebooting. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic bool __init 698c2ecf20Sopenharmony_citest_int_hash(unsigned long long h64, u32 hash_or[2][33]) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int k; 728c2ecf20Sopenharmony_ci u32 h0 = (u32)h64, h1, h2; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Test __hash32 */ 758c2ecf20Sopenharmony_ci hash_or[0][0] |= h1 = __hash_32(h0); 768c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH__HASH_32 778c2ecf20Sopenharmony_ci hash_or[1][0] |= h2 = __hash_32_generic(h0); 788c2ecf20Sopenharmony_ci#if HAVE_ARCH__HASH_32 == 1 798c2ecf20Sopenharmony_ci if (h1 != h2) { 808c2ecf20Sopenharmony_ci pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x", 818c2ecf20Sopenharmony_ci h0, h1, h2); 828c2ecf20Sopenharmony_ci return false; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci#endif 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* Test k = 1..32 bits */ 888c2ecf20Sopenharmony_ci for (k = 1; k <= 32; k++) { 898c2ecf20Sopenharmony_ci u32 const m = ((u32)2 << (k-1)) - 1; /* Low k bits set */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Test hash_32 */ 928c2ecf20Sopenharmony_ci hash_or[0][k] |= h1 = hash_32(h0, k); 938c2ecf20Sopenharmony_ci if (h1 > m) { 948c2ecf20Sopenharmony_ci pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m); 958c2ecf20Sopenharmony_ci return false; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH_HASH_32 988c2ecf20Sopenharmony_ci h2 = hash_32_generic(h0, k); 998c2ecf20Sopenharmony_ci#if HAVE_ARCH_HASH_32 == 1 1008c2ecf20Sopenharmony_ci if (h1 != h2) { 1018c2ecf20Sopenharmony_ci pr_err("hash_32(%#x, %d) = %#x != hash_32_generic() " 1028c2ecf20Sopenharmony_ci " = %#x", h0, k, h1, h2); 1038c2ecf20Sopenharmony_ci return false; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci#else 1068c2ecf20Sopenharmony_ci if (h2 > m) { 1078c2ecf20Sopenharmony_ci pr_err("hash_32_generic(%#x, %d) = %#x > %#x", 1088c2ecf20Sopenharmony_ci h0, k, h1, m); 1098c2ecf20Sopenharmony_ci return false; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci#endif 1138c2ecf20Sopenharmony_ci /* Test hash_64 */ 1148c2ecf20Sopenharmony_ci hash_or[1][k] |= h1 = hash_64(h64, k); 1158c2ecf20Sopenharmony_ci if (h1 > m) { 1168c2ecf20Sopenharmony_ci pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, h1, m); 1178c2ecf20Sopenharmony_ci return false; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH_HASH_64 1208c2ecf20Sopenharmony_ci h2 = hash_64_generic(h64, k); 1218c2ecf20Sopenharmony_ci#if HAVE_ARCH_HASH_64 == 1 1228c2ecf20Sopenharmony_ci if (h1 != h2) { 1238c2ecf20Sopenharmony_ci pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() " 1248c2ecf20Sopenharmony_ci "= %#x", h64, k, h1, h2); 1258c2ecf20Sopenharmony_ci return false; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci#else 1288c2ecf20Sopenharmony_ci if (h2 > m) { 1298c2ecf20Sopenharmony_ci pr_err("hash_64_generic(%#llx, %d) = %#x > %#x", 1308c2ecf20Sopenharmony_ci h64, k, h1, m); 1318c2ecf20Sopenharmony_ci return false; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci#endif 1348c2ecf20Sopenharmony_ci#endif 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci (void)h2; /* Suppress unused variable warning */ 1388c2ecf20Sopenharmony_ci return true; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define SIZE 256 /* Run time is cubic in SIZE */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int __init 1448c2ecf20Sopenharmony_citest_hash_init(void) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci char buf[SIZE+1]; 1478c2ecf20Sopenharmony_ci u32 string_or = 0, hash_or[2][33] = { { 0, } }; 1488c2ecf20Sopenharmony_ci unsigned tests = 0; 1498c2ecf20Sopenharmony_ci unsigned long long h64 = 0; 1508c2ecf20Sopenharmony_ci int i, j; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci fill_buf(buf, SIZE, 1); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Test every possible non-empty substring in the buffer. */ 1558c2ecf20Sopenharmony_ci for (j = SIZE; j > 0; --j) { 1568c2ecf20Sopenharmony_ci buf[j] = '\0'; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci for (i = 0; i <= j; i++) { 1598c2ecf20Sopenharmony_ci u64 hashlen = hashlen_string(buf+i, buf+i); 1608c2ecf20Sopenharmony_ci u32 h0 = full_name_hash(buf+i, buf+i, j-i); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Check that hashlen_string gets the length right */ 1638c2ecf20Sopenharmony_ci if (hashlen_len(hashlen) != j-i) { 1648c2ecf20Sopenharmony_ci pr_err("hashlen_string(%d..%d) returned length" 1658c2ecf20Sopenharmony_ci " %u, expected %d", 1668c2ecf20Sopenharmony_ci i, j, hashlen_len(hashlen), j-i); 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci /* Check that the hashes match */ 1708c2ecf20Sopenharmony_ci if (hashlen_hash(hashlen) != h0) { 1718c2ecf20Sopenharmony_ci pr_err("hashlen_string(%d..%d) = %08x != " 1728c2ecf20Sopenharmony_ci "full_name_hash() = %08x", 1738c2ecf20Sopenharmony_ci i, j, hashlen_hash(hashlen), h0); 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci string_or |= h0; 1788c2ecf20Sopenharmony_ci h64 = h64 << 32 | h0; /* For use with hash_64 */ 1798c2ecf20Sopenharmony_ci if (!test_int_hash(h64, hash_or)) 1808c2ecf20Sopenharmony_ci return -EINVAL; 1818c2ecf20Sopenharmony_ci tests++; 1828c2ecf20Sopenharmony_ci } /* i */ 1838c2ecf20Sopenharmony_ci } /* j */ 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* The OR of all the hash values should cover all the bits */ 1868c2ecf20Sopenharmony_ci if (~string_or) { 1878c2ecf20Sopenharmony_ci pr_err("OR of all string hash results = %#x != %#x", 1888c2ecf20Sopenharmony_ci string_or, -1u); 1898c2ecf20Sopenharmony_ci return -EINVAL; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci if (~hash_or[0][0]) { 1928c2ecf20Sopenharmony_ci pr_err("OR of all __hash_32 results = %#x != %#x", 1938c2ecf20Sopenharmony_ci hash_or[0][0], -1u); 1948c2ecf20Sopenharmony_ci return -EINVAL; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH__HASH_32 1978c2ecf20Sopenharmony_ci#if HAVE_ARCH__HASH_32 != 1 /* Test is pointless if results match */ 1988c2ecf20Sopenharmony_ci if (~hash_or[1][0]) { 1998c2ecf20Sopenharmony_ci pr_err("OR of all __hash_32_generic results = %#x != %#x", 2008c2ecf20Sopenharmony_ci hash_or[1][0], -1u); 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci#endif 2048c2ecf20Sopenharmony_ci#endif 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Likewise for all the i-bit hash values */ 2078c2ecf20Sopenharmony_ci for (i = 1; i <= 32; i++) { 2088c2ecf20Sopenharmony_ci u32 const m = ((u32)2 << (i-1)) - 1; /* Low i bits set */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (hash_or[0][i] != m) { 2118c2ecf20Sopenharmony_ci pr_err("OR of all hash_32(%d) results = %#x " 2128c2ecf20Sopenharmony_ci "(%#x expected)", i, hash_or[0][i], m); 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci if (hash_or[1][i] != m) { 2168c2ecf20Sopenharmony_ci pr_err("OR of all hash_64(%d) results = %#x " 2178c2ecf20Sopenharmony_ci "(%#x expected)", i, hash_or[1][i], m); 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Issue notices about skipped tests. */ 2238c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH__HASH_32 2248c2ecf20Sopenharmony_ci#if HAVE_ARCH__HASH_32 != 1 2258c2ecf20Sopenharmony_ci pr_info("__hash_32() is arch-specific; not compared to generic."); 2268c2ecf20Sopenharmony_ci#endif 2278c2ecf20Sopenharmony_ci#else 2288c2ecf20Sopenharmony_ci pr_info("__hash_32() has no arch implementation to test."); 2298c2ecf20Sopenharmony_ci#endif 2308c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH_HASH_32 2318c2ecf20Sopenharmony_ci#if HAVE_ARCH_HASH_32 != 1 2328c2ecf20Sopenharmony_ci pr_info("hash_32() is arch-specific; not compared to generic."); 2338c2ecf20Sopenharmony_ci#endif 2348c2ecf20Sopenharmony_ci#else 2358c2ecf20Sopenharmony_ci pr_info("hash_32() has no arch implementation to test."); 2368c2ecf20Sopenharmony_ci#endif 2378c2ecf20Sopenharmony_ci#ifdef HAVE_ARCH_HASH_64 2388c2ecf20Sopenharmony_ci#if HAVE_ARCH_HASH_64 != 1 2398c2ecf20Sopenharmony_ci pr_info("hash_64() is arch-specific; not compared to generic."); 2408c2ecf20Sopenharmony_ci#endif 2418c2ecf20Sopenharmony_ci#else 2428c2ecf20Sopenharmony_ci pr_info("hash_64() has no arch implementation to test."); 2438c2ecf20Sopenharmony_ci#endif 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci pr_notice("%u tests passed.", tests); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void __exit test_hash_exit(void) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cimodule_init(test_hash_init); /* Does everything */ 2558c2ecf20Sopenharmony_cimodule_exit(test_hash_exit); /* Does nothing */ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 258