1*af53e85eSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-or-later 2*af53e85eSChristoph Hellwig /* 3*af53e85eSChristoph Hellwig * Unit test the XOR library functions. 4*af53e85eSChristoph Hellwig * 5*af53e85eSChristoph Hellwig * Copyright 2024 Google LLC 6*af53e85eSChristoph Hellwig * Copyright 2026 Christoph Hellwig 7*af53e85eSChristoph Hellwig * 8*af53e85eSChristoph Hellwig * Based on the CRC tests by Eric Biggers <ebiggers@google.com>. 9*af53e85eSChristoph Hellwig */ 10*af53e85eSChristoph Hellwig #include <kunit/test.h> 11*af53e85eSChristoph Hellwig #include <linux/prandom.h> 12*af53e85eSChristoph Hellwig #include <linux/string_choices.h> 13*af53e85eSChristoph Hellwig #include <linux/vmalloc.h> 14*af53e85eSChristoph Hellwig #include <linux/raid/xor.h> 15*af53e85eSChristoph Hellwig 16*af53e85eSChristoph Hellwig #define XOR_KUNIT_SEED 42 17*af53e85eSChristoph Hellwig #define XOR_KUNIT_MAX_BYTES 16384 18*af53e85eSChristoph Hellwig #define XOR_KUNIT_MAX_BUFFERS 64 19*af53e85eSChristoph Hellwig #define XOR_KUNIT_NUM_TEST_ITERS 1000 20*af53e85eSChristoph Hellwig 21*af53e85eSChristoph Hellwig static struct rnd_state rng; 22*af53e85eSChristoph Hellwig static void *test_buffers[XOR_KUNIT_MAX_BUFFERS]; 23*af53e85eSChristoph Hellwig static void *test_dest; 24*af53e85eSChristoph Hellwig static void *test_ref; 25*af53e85eSChristoph Hellwig static size_t test_buflen; 26*af53e85eSChristoph Hellwig 27*af53e85eSChristoph Hellwig static u32 rand32(void) 28*af53e85eSChristoph Hellwig { 29*af53e85eSChristoph Hellwig return prandom_u32_state(&rng); 30*af53e85eSChristoph Hellwig } 31*af53e85eSChristoph Hellwig 32*af53e85eSChristoph Hellwig /* Reference implementation using dumb byte-wise XOR */ 33*af53e85eSChristoph Hellwig static void xor_ref(void *dest, void **srcs, unsigned int src_cnt, 34*af53e85eSChristoph Hellwig unsigned int bytes) 35*af53e85eSChristoph Hellwig { 36*af53e85eSChristoph Hellwig unsigned int off, idx; 37*af53e85eSChristoph Hellwig u8 *d = dest; 38*af53e85eSChristoph Hellwig 39*af53e85eSChristoph Hellwig for (off = 0; off < bytes; off++) { 40*af53e85eSChristoph Hellwig for (idx = 0; idx < src_cnt; idx++) { 41*af53e85eSChristoph Hellwig u8 *src = srcs[idx]; 42*af53e85eSChristoph Hellwig 43*af53e85eSChristoph Hellwig d[off] ^= src[off]; 44*af53e85eSChristoph Hellwig } 45*af53e85eSChristoph Hellwig } 46*af53e85eSChristoph Hellwig } 47*af53e85eSChristoph Hellwig 48*af53e85eSChristoph Hellwig /* Generate a random length that is a multiple of 512. */ 49*af53e85eSChristoph Hellwig static unsigned int random_length(unsigned int max_length) 50*af53e85eSChristoph Hellwig { 51*af53e85eSChristoph Hellwig return round_up((rand32() % max_length) + 1, 512); 52*af53e85eSChristoph Hellwig } 53*af53e85eSChristoph Hellwig 54*af53e85eSChristoph Hellwig /* Generate a random alignment that is a multiple of 64. */ 55*af53e85eSChristoph Hellwig static unsigned int random_alignment(unsigned int max_alignment) 56*af53e85eSChristoph Hellwig { 57*af53e85eSChristoph Hellwig return ((rand32() % max_alignment) + 1) & ~63; 58*af53e85eSChristoph Hellwig } 59*af53e85eSChristoph Hellwig 60*af53e85eSChristoph Hellwig static void xor_generate_random_data(void) 61*af53e85eSChristoph Hellwig { 62*af53e85eSChristoph Hellwig int i; 63*af53e85eSChristoph Hellwig 64*af53e85eSChristoph Hellwig prandom_bytes_state(&rng, test_dest, test_buflen); 65*af53e85eSChristoph Hellwig memcpy(test_ref, test_dest, test_buflen); 66*af53e85eSChristoph Hellwig for (i = 0; i < XOR_KUNIT_MAX_BUFFERS; i++) 67*af53e85eSChristoph Hellwig prandom_bytes_state(&rng, test_buffers[i], test_buflen); 68*af53e85eSChristoph Hellwig } 69*af53e85eSChristoph Hellwig 70*af53e85eSChristoph Hellwig /* Test that xor_gen gives the same result as a reference implementation. */ 71*af53e85eSChristoph Hellwig static void xor_test(struct kunit *test) 72*af53e85eSChristoph Hellwig { 73*af53e85eSChristoph Hellwig void *aligned_buffers[XOR_KUNIT_MAX_BUFFERS]; 74*af53e85eSChristoph Hellwig size_t i; 75*af53e85eSChristoph Hellwig 76*af53e85eSChristoph Hellwig for (i = 0; i < XOR_KUNIT_NUM_TEST_ITERS; i++) { 77*af53e85eSChristoph Hellwig unsigned int nr_buffers = 78*af53e85eSChristoph Hellwig (rand32() % XOR_KUNIT_MAX_BUFFERS) + 1; 79*af53e85eSChristoph Hellwig unsigned int len = random_length(XOR_KUNIT_MAX_BYTES); 80*af53e85eSChristoph Hellwig unsigned int max_alignment, align = 0; 81*af53e85eSChristoph Hellwig void *buffers; 82*af53e85eSChristoph Hellwig 83*af53e85eSChristoph Hellwig if (rand32() % 8 == 0) 84*af53e85eSChristoph Hellwig /* Refresh the data occasionally. */ 85*af53e85eSChristoph Hellwig xor_generate_random_data(); 86*af53e85eSChristoph Hellwig 87*af53e85eSChristoph Hellwig /* 88*af53e85eSChristoph Hellwig * If we're not using the entire buffer size, inject randomize 89*af53e85eSChristoph Hellwig * alignment into the buffer. 90*af53e85eSChristoph Hellwig */ 91*af53e85eSChristoph Hellwig max_alignment = XOR_KUNIT_MAX_BYTES - len; 92*af53e85eSChristoph Hellwig if (max_alignment == 0) { 93*af53e85eSChristoph Hellwig buffers = test_buffers; 94*af53e85eSChristoph Hellwig } else if (rand32() % 2 == 0) { 95*af53e85eSChristoph Hellwig /* Use random alignments mod 64 */ 96*af53e85eSChristoph Hellwig int j; 97*af53e85eSChristoph Hellwig 98*af53e85eSChristoph Hellwig for (j = 0; j < nr_buffers; j++) 99*af53e85eSChristoph Hellwig aligned_buffers[j] = test_buffers[j] + 100*af53e85eSChristoph Hellwig random_alignment(max_alignment); 101*af53e85eSChristoph Hellwig buffers = aligned_buffers; 102*af53e85eSChristoph Hellwig align = random_alignment(max_alignment); 103*af53e85eSChristoph Hellwig } else { 104*af53e85eSChristoph Hellwig /* Go up to the guard page, to catch buffer overreads */ 105*af53e85eSChristoph Hellwig int j; 106*af53e85eSChristoph Hellwig 107*af53e85eSChristoph Hellwig align = test_buflen - len; 108*af53e85eSChristoph Hellwig for (j = 0; j < nr_buffers; j++) 109*af53e85eSChristoph Hellwig aligned_buffers[j] = test_buffers[j] + align; 110*af53e85eSChristoph Hellwig buffers = aligned_buffers; 111*af53e85eSChristoph Hellwig } 112*af53e85eSChristoph Hellwig 113*af53e85eSChristoph Hellwig /* 114*af53e85eSChristoph Hellwig * Compute the XOR, and verify that it equals the XOR computed 115*af53e85eSChristoph Hellwig * by a simple byte-at-a-time reference implementation. 116*af53e85eSChristoph Hellwig */ 117*af53e85eSChristoph Hellwig xor_ref(test_ref + align, buffers, nr_buffers, len); 118*af53e85eSChristoph Hellwig xor_gen(test_dest + align, buffers, nr_buffers, len); 119*af53e85eSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, test_ref + align, 120*af53e85eSChristoph Hellwig test_dest + align, len, 121*af53e85eSChristoph Hellwig "Wrong result with buffers=%u, len=%u, unaligned=%s, at_end=%s", 122*af53e85eSChristoph Hellwig nr_buffers, len, 123*af53e85eSChristoph Hellwig str_yes_no(max_alignment), 124*af53e85eSChristoph Hellwig str_yes_no(align + len == test_buflen)); 125*af53e85eSChristoph Hellwig } 126*af53e85eSChristoph Hellwig } 127*af53e85eSChristoph Hellwig 128*af53e85eSChristoph Hellwig static struct kunit_case xor_test_cases[] = { 129*af53e85eSChristoph Hellwig KUNIT_CASE(xor_test), 130*af53e85eSChristoph Hellwig {}, 131*af53e85eSChristoph Hellwig }; 132*af53e85eSChristoph Hellwig 133*af53e85eSChristoph Hellwig static int xor_suite_init(struct kunit_suite *suite) 134*af53e85eSChristoph Hellwig { 135*af53e85eSChristoph Hellwig int i; 136*af53e85eSChristoph Hellwig 137*af53e85eSChristoph Hellwig /* 138*af53e85eSChristoph Hellwig * Allocate the test buffer using vmalloc() with a page-aligned length 139*af53e85eSChristoph Hellwig * so that it is immediately followed by a guard page. This allows 140*af53e85eSChristoph Hellwig * buffer overreads to be detected, even in assembly code. 141*af53e85eSChristoph Hellwig */ 142*af53e85eSChristoph Hellwig test_buflen = round_up(XOR_KUNIT_MAX_BYTES, PAGE_SIZE); 143*af53e85eSChristoph Hellwig test_ref = vmalloc(test_buflen); 144*af53e85eSChristoph Hellwig if (!test_ref) 145*af53e85eSChristoph Hellwig return -ENOMEM; 146*af53e85eSChristoph Hellwig test_dest = vmalloc(test_buflen); 147*af53e85eSChristoph Hellwig if (!test_dest) 148*af53e85eSChristoph Hellwig goto out_free_ref; 149*af53e85eSChristoph Hellwig for (i = 0; i < XOR_KUNIT_MAX_BUFFERS; i++) { 150*af53e85eSChristoph Hellwig test_buffers[i] = vmalloc(test_buflen); 151*af53e85eSChristoph Hellwig if (!test_buffers[i]) 152*af53e85eSChristoph Hellwig goto out_free_buffers; 153*af53e85eSChristoph Hellwig } 154*af53e85eSChristoph Hellwig 155*af53e85eSChristoph Hellwig prandom_seed_state(&rng, XOR_KUNIT_SEED); 156*af53e85eSChristoph Hellwig xor_generate_random_data(); 157*af53e85eSChristoph Hellwig return 0; 158*af53e85eSChristoph Hellwig 159*af53e85eSChristoph Hellwig out_free_buffers: 160*af53e85eSChristoph Hellwig while (--i >= 0) 161*af53e85eSChristoph Hellwig vfree(test_buffers[i]); 162*af53e85eSChristoph Hellwig vfree(test_dest); 163*af53e85eSChristoph Hellwig out_free_ref: 164*af53e85eSChristoph Hellwig vfree(test_ref); 165*af53e85eSChristoph Hellwig return -ENOMEM; 166*af53e85eSChristoph Hellwig } 167*af53e85eSChristoph Hellwig 168*af53e85eSChristoph Hellwig static void xor_suite_exit(struct kunit_suite *suite) 169*af53e85eSChristoph Hellwig { 170*af53e85eSChristoph Hellwig int i; 171*af53e85eSChristoph Hellwig 172*af53e85eSChristoph Hellwig vfree(test_ref); 173*af53e85eSChristoph Hellwig vfree(test_dest); 174*af53e85eSChristoph Hellwig for (i = 0; i < XOR_KUNIT_MAX_BUFFERS; i++) 175*af53e85eSChristoph Hellwig vfree(test_buffers[i]); 176*af53e85eSChristoph Hellwig } 177*af53e85eSChristoph Hellwig 178*af53e85eSChristoph Hellwig static struct kunit_suite xor_test_suite = { 179*af53e85eSChristoph Hellwig .name = "xor", 180*af53e85eSChristoph Hellwig .test_cases = xor_test_cases, 181*af53e85eSChristoph Hellwig .suite_init = xor_suite_init, 182*af53e85eSChristoph Hellwig .suite_exit = xor_suite_exit, 183*af53e85eSChristoph Hellwig }; 184*af53e85eSChristoph Hellwig kunit_test_suite(xor_test_suite); 185*af53e85eSChristoph Hellwig 186*af53e85eSChristoph Hellwig MODULE_DESCRIPTION("Unit test for the XOR library functions"); 187*af53e85eSChristoph Hellwig MODULE_LICENSE("GPL"); 188