1*3626738bSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-or-later 2*3626738bSChristoph Hellwig /* 3*3626738bSChristoph Hellwig * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved 4*3626738bSChristoph Hellwig * 5*3626738bSChristoph Hellwig * Test RAID-6 recovery algorithms. 6*3626738bSChristoph Hellwig */ 7*3626738bSChristoph Hellwig 8*3626738bSChristoph Hellwig #include <kunit/test.h> 9*3626738bSChristoph Hellwig #include <linux/prandom.h> 10*3626738bSChristoph Hellwig #include <linux/raid/pq.h> 11*3626738bSChristoph Hellwig 12*3626738bSChristoph Hellwig MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 13*3626738bSChristoph Hellwig 14*3626738bSChristoph Hellwig #define RAID6_KUNIT_SEED 42 15*3626738bSChristoph Hellwig 16*3626738bSChristoph Hellwig #define NDISKS 16 /* Including P and Q */ 17*3626738bSChristoph Hellwig 18*3626738bSChristoph Hellwig static struct rnd_state rng; 19*3626738bSChristoph Hellwig static void *dataptrs[NDISKS]; 20*3626738bSChristoph Hellwig static char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 21*3626738bSChristoph Hellwig static char recovi[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 22*3626738bSChristoph Hellwig static char recovj[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 23*3626738bSChristoph Hellwig 24*3626738bSChristoph Hellwig static void makedata(int start, int stop) 25*3626738bSChristoph Hellwig { 26*3626738bSChristoph Hellwig int i; 27*3626738bSChristoph Hellwig 28*3626738bSChristoph Hellwig for (i = start; i <= stop; i++) { 29*3626738bSChristoph Hellwig prandom_bytes_state(&rng, data[i], PAGE_SIZE); 30*3626738bSChristoph Hellwig dataptrs[i] = data[i]; 31*3626738bSChristoph Hellwig } 32*3626738bSChristoph Hellwig } 33*3626738bSChristoph Hellwig 34*3626738bSChristoph Hellwig static char member_type(int d) 35*3626738bSChristoph Hellwig { 36*3626738bSChristoph Hellwig switch (d) { 37*3626738bSChristoph Hellwig case NDISKS-2: 38*3626738bSChristoph Hellwig return 'P'; 39*3626738bSChristoph Hellwig case NDISKS-1: 40*3626738bSChristoph Hellwig return 'Q'; 41*3626738bSChristoph Hellwig default: 42*3626738bSChristoph Hellwig return 'D'; 43*3626738bSChristoph Hellwig } 44*3626738bSChristoph Hellwig } 45*3626738bSChristoph Hellwig 46*3626738bSChristoph Hellwig static void test_disks(struct kunit *test, const struct raid6_calls *calls, 47*3626738bSChristoph Hellwig const struct raid6_recov_calls *ra, int faila, int failb) 48*3626738bSChristoph Hellwig { 49*3626738bSChristoph Hellwig memset(recovi, 0xf0, PAGE_SIZE); 50*3626738bSChristoph Hellwig memset(recovj, 0xba, PAGE_SIZE); 51*3626738bSChristoph Hellwig 52*3626738bSChristoph Hellwig dataptrs[faila] = recovi; 53*3626738bSChristoph Hellwig dataptrs[failb] = recovj; 54*3626738bSChristoph Hellwig 55*3626738bSChristoph Hellwig if (failb == NDISKS - 1) { 56*3626738bSChristoph Hellwig /* 57*3626738bSChristoph Hellwig * We don't implement the data+Q failure scenario, since it 58*3626738bSChristoph Hellwig * is equivalent to a RAID-5 failure (XOR, then recompute Q). 59*3626738bSChristoph Hellwig */ 60*3626738bSChristoph Hellwig if (faila != NDISKS - 2) 61*3626738bSChristoph Hellwig goto skip; 62*3626738bSChristoph Hellwig 63*3626738bSChristoph Hellwig /* P+Q failure. Just rebuild the syndrome. */ 64*3626738bSChristoph Hellwig calls->gen_syndrome(NDISKS, PAGE_SIZE, dataptrs); 65*3626738bSChristoph Hellwig } else if (failb == NDISKS - 2) { 66*3626738bSChristoph Hellwig /* data+P failure. */ 67*3626738bSChristoph Hellwig ra->datap(NDISKS, PAGE_SIZE, faila, dataptrs); 68*3626738bSChristoph Hellwig } else { 69*3626738bSChristoph Hellwig /* data+data failure. */ 70*3626738bSChristoph Hellwig ra->data2(NDISKS, PAGE_SIZE, faila, failb, dataptrs); 71*3626738bSChristoph Hellwig } 72*3626738bSChristoph Hellwig 73*3626738bSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, data[faila], recovi, PAGE_SIZE, 74*3626738bSChristoph Hellwig "algo=%-8s/%-8s faila miscompared: %3d[%c] (failb=%3d[%c])\n", 75*3626738bSChristoph Hellwig calls->name, ra->name, 76*3626738bSChristoph Hellwig faila, member_type(faila), 77*3626738bSChristoph Hellwig failb, member_type(failb)); 78*3626738bSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, data[failb], recovj, PAGE_SIZE, 79*3626738bSChristoph Hellwig "algo=%-8s/%-8s failb miscompared: %3d[%c] (faila=%3d[%c])\n", 80*3626738bSChristoph Hellwig calls->name, ra->name, 81*3626738bSChristoph Hellwig failb, member_type(failb), 82*3626738bSChristoph Hellwig faila, member_type(faila)); 83*3626738bSChristoph Hellwig 84*3626738bSChristoph Hellwig skip: 85*3626738bSChristoph Hellwig dataptrs[faila] = data[faila]; 86*3626738bSChristoph Hellwig dataptrs[failb] = data[failb]; 87*3626738bSChristoph Hellwig } 88*3626738bSChristoph Hellwig 89*3626738bSChristoph Hellwig static void raid6_test(struct kunit *test) 90*3626738bSChristoph Hellwig { 91*3626738bSChristoph Hellwig const struct raid6_calls *const *algo; 92*3626738bSChristoph Hellwig const struct raid6_recov_calls *const *ra; 93*3626738bSChristoph Hellwig int i, j, p1, p2; 94*3626738bSChristoph Hellwig 95*3626738bSChristoph Hellwig for (ra = raid6_recov_algos; *ra; ra++) { 96*3626738bSChristoph Hellwig if ((*ra)->valid && !(*ra)->valid()) 97*3626738bSChristoph Hellwig continue; 98*3626738bSChristoph Hellwig 99*3626738bSChristoph Hellwig for (algo = raid6_algos; *algo; algo++) { 100*3626738bSChristoph Hellwig const struct raid6_calls *calls = *algo; 101*3626738bSChristoph Hellwig 102*3626738bSChristoph Hellwig if (calls->valid && !calls->valid()) 103*3626738bSChristoph Hellwig continue; 104*3626738bSChristoph Hellwig 105*3626738bSChristoph Hellwig /* Nuke syndromes */ 106*3626738bSChristoph Hellwig memset(data[NDISKS - 2], 0xee, PAGE_SIZE); 107*3626738bSChristoph Hellwig memset(data[NDISKS - 1], 0xee, PAGE_SIZE); 108*3626738bSChristoph Hellwig 109*3626738bSChristoph Hellwig /* Generate assumed good syndrome */ 110*3626738bSChristoph Hellwig calls->gen_syndrome(NDISKS, PAGE_SIZE, 111*3626738bSChristoph Hellwig (void **)&dataptrs); 112*3626738bSChristoph Hellwig 113*3626738bSChristoph Hellwig for (i = 0; i < NDISKS-1; i++) 114*3626738bSChristoph Hellwig for (j = i+1; j < NDISKS; j++) 115*3626738bSChristoph Hellwig test_disks(test, calls, *ra, i, j); 116*3626738bSChristoph Hellwig 117*3626738bSChristoph Hellwig if (!calls->xor_syndrome) 118*3626738bSChristoph Hellwig continue; 119*3626738bSChristoph Hellwig 120*3626738bSChristoph Hellwig for (p1 = 0; p1 < NDISKS-2; p1++) 121*3626738bSChristoph Hellwig for (p2 = p1; p2 < NDISKS-2; p2++) { 122*3626738bSChristoph Hellwig 123*3626738bSChristoph Hellwig /* Simulate rmw run */ 124*3626738bSChristoph Hellwig calls->xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 125*3626738bSChristoph Hellwig (void **)&dataptrs); 126*3626738bSChristoph Hellwig makedata(p1, p2); 127*3626738bSChristoph Hellwig calls->xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 128*3626738bSChristoph Hellwig (void **)&dataptrs); 129*3626738bSChristoph Hellwig 130*3626738bSChristoph Hellwig for (i = 0; i < NDISKS-1; i++) 131*3626738bSChristoph Hellwig for (j = i+1; j < NDISKS; j++) 132*3626738bSChristoph Hellwig test_disks(test, calls, 133*3626738bSChristoph Hellwig *ra, i, j); 134*3626738bSChristoph Hellwig } 135*3626738bSChristoph Hellwig 136*3626738bSChristoph Hellwig } 137*3626738bSChristoph Hellwig } 138*3626738bSChristoph Hellwig } 139*3626738bSChristoph Hellwig 140*3626738bSChristoph Hellwig static struct kunit_case raid6_test_cases[] = { 141*3626738bSChristoph Hellwig KUNIT_CASE(raid6_test), 142*3626738bSChristoph Hellwig {}, 143*3626738bSChristoph Hellwig }; 144*3626738bSChristoph Hellwig 145*3626738bSChristoph Hellwig static int raid6_suite_init(struct kunit_suite *suite) 146*3626738bSChristoph Hellwig { 147*3626738bSChristoph Hellwig prandom_seed_state(&rng, RAID6_KUNIT_SEED); 148*3626738bSChristoph Hellwig makedata(0, NDISKS - 1); 149*3626738bSChristoph Hellwig return 0; 150*3626738bSChristoph Hellwig } 151*3626738bSChristoph Hellwig 152*3626738bSChristoph Hellwig static struct kunit_suite raid6_test_suite = { 153*3626738bSChristoph Hellwig .name = "raid6", 154*3626738bSChristoph Hellwig .test_cases = raid6_test_cases, 155*3626738bSChristoph Hellwig .suite_init = raid6_suite_init, 156*3626738bSChristoph Hellwig }; 157*3626738bSChristoph Hellwig kunit_test_suite(raid6_test_suite); 158*3626738bSChristoph Hellwig 159*3626738bSChristoph Hellwig MODULE_DESCRIPTION("Unit test for the RAID P/Q library functions"); 160*3626738bSChristoph Hellwig MODULE_LICENSE("GPL"); 161