13626738bSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-or-later 23626738bSChristoph Hellwig /* 33626738bSChristoph Hellwig * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved 43626738bSChristoph Hellwig * 53626738bSChristoph Hellwig * Test RAID-6 recovery algorithms. 63626738bSChristoph Hellwig */ 73626738bSChristoph Hellwig 83626738bSChristoph Hellwig #include <kunit/test.h> 93626738bSChristoph Hellwig #include <linux/prandom.h> 10769d603fSChristoph Hellwig #include "../algos.h" 113626738bSChristoph Hellwig 123626738bSChristoph Hellwig MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 133626738bSChristoph Hellwig 143626738bSChristoph Hellwig #define RAID6_KUNIT_SEED 42 153626738bSChristoph Hellwig 163626738bSChristoph Hellwig #define NDISKS 16 /* Including P and Q */ 173626738bSChristoph Hellwig 183626738bSChristoph Hellwig static struct rnd_state rng; 193626738bSChristoph Hellwig static void *dataptrs[NDISKS]; 203626738bSChristoph Hellwig static char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 213626738bSChristoph Hellwig static char recovi[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 223626738bSChristoph Hellwig static char recovj[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 233626738bSChristoph Hellwig 24*2175395fSChristoph Hellwig struct test_args { 25*2175395fSChristoph Hellwig unsigned int recov_idx; 26*2175395fSChristoph Hellwig const struct raid6_recov_calls *recov; 27*2175395fSChristoph Hellwig unsigned int gen_idx; 28*2175395fSChristoph Hellwig const struct raid6_calls *gen; 29*2175395fSChristoph Hellwig }; 30*2175395fSChristoph Hellwig 31*2175395fSChristoph Hellwig static struct test_args args; 32*2175395fSChristoph Hellwig 333626738bSChristoph Hellwig static void makedata(int start, int stop) 343626738bSChristoph Hellwig { 353626738bSChristoph Hellwig int i; 363626738bSChristoph Hellwig 373626738bSChristoph Hellwig for (i = start; i <= stop; i++) { 383626738bSChristoph Hellwig prandom_bytes_state(&rng, data[i], PAGE_SIZE); 393626738bSChristoph Hellwig dataptrs[i] = data[i]; 403626738bSChristoph Hellwig } 413626738bSChristoph Hellwig } 423626738bSChristoph Hellwig 433626738bSChristoph Hellwig static char member_type(int d) 443626738bSChristoph Hellwig { 453626738bSChristoph Hellwig switch (d) { 463626738bSChristoph Hellwig case NDISKS-2: 473626738bSChristoph Hellwig return 'P'; 483626738bSChristoph Hellwig case NDISKS-1: 493626738bSChristoph Hellwig return 'Q'; 503626738bSChristoph Hellwig default: 513626738bSChristoph Hellwig return 'D'; 523626738bSChristoph Hellwig } 533626738bSChristoph Hellwig } 543626738bSChristoph Hellwig 55*2175395fSChristoph Hellwig static void test_recover(struct kunit *test, int faila, int failb) 563626738bSChristoph Hellwig { 57*2175395fSChristoph Hellwig const struct test_args *ta = test->param_value; 58*2175395fSChristoph Hellwig 593626738bSChristoph Hellwig memset(recovi, 0xf0, PAGE_SIZE); 603626738bSChristoph Hellwig memset(recovj, 0xba, PAGE_SIZE); 613626738bSChristoph Hellwig 623626738bSChristoph Hellwig dataptrs[faila] = recovi; 633626738bSChristoph Hellwig dataptrs[failb] = recovj; 643626738bSChristoph Hellwig 653626738bSChristoph Hellwig if (failb == NDISKS - 1) { 663626738bSChristoph Hellwig /* 673626738bSChristoph Hellwig * We don't implement the data+Q failure scenario, since it 683626738bSChristoph Hellwig * is equivalent to a RAID-5 failure (XOR, then recompute Q). 693626738bSChristoph Hellwig */ 703626738bSChristoph Hellwig if (faila != NDISKS - 2) 713626738bSChristoph Hellwig goto skip; 723626738bSChristoph Hellwig 733626738bSChristoph Hellwig /* P+Q failure. Just rebuild the syndrome. */ 74*2175395fSChristoph Hellwig ta->gen->gen_syndrome(NDISKS, PAGE_SIZE, dataptrs); 753626738bSChristoph Hellwig } else if (failb == NDISKS - 2) { 763626738bSChristoph Hellwig /* data+P failure. */ 77*2175395fSChristoph Hellwig ta->recov->datap(NDISKS, PAGE_SIZE, faila, dataptrs); 783626738bSChristoph Hellwig } else { 793626738bSChristoph Hellwig /* data+data failure. */ 80*2175395fSChristoph Hellwig ta->recov->data2(NDISKS, PAGE_SIZE, faila, failb, dataptrs); 813626738bSChristoph Hellwig } 823626738bSChristoph Hellwig 833626738bSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, data[faila], recovi, PAGE_SIZE, 84*2175395fSChristoph Hellwig "faila miscompared: %3d[%c] (failb=%3d[%c])\n", 853626738bSChristoph Hellwig faila, member_type(faila), 863626738bSChristoph Hellwig failb, member_type(failb)); 873626738bSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, data[failb], recovj, PAGE_SIZE, 88*2175395fSChristoph Hellwig "failb miscompared: %3d[%c] (faila=%3d[%c])\n", 893626738bSChristoph Hellwig failb, member_type(failb), 903626738bSChristoph Hellwig faila, member_type(faila)); 913626738bSChristoph Hellwig 923626738bSChristoph Hellwig skip: 933626738bSChristoph Hellwig dataptrs[faila] = data[faila]; 943626738bSChristoph Hellwig dataptrs[failb] = data[failb]; 953626738bSChristoph Hellwig } 963626738bSChristoph Hellwig 973626738bSChristoph Hellwig static void raid6_test(struct kunit *test) 983626738bSChristoph Hellwig { 99*2175395fSChristoph Hellwig const struct test_args *ta = test->param_value; 1003626738bSChristoph Hellwig int i, j, p1, p2; 1013626738bSChristoph Hellwig 1023626738bSChristoph Hellwig /* Nuke syndromes */ 1033626738bSChristoph Hellwig memset(data[NDISKS - 2], 0xee, PAGE_SIZE); 1043626738bSChristoph Hellwig memset(data[NDISKS - 1], 0xee, PAGE_SIZE); 1053626738bSChristoph Hellwig 1063626738bSChristoph Hellwig /* Generate assumed good syndrome */ 107*2175395fSChristoph Hellwig ta->gen->gen_syndrome(NDISKS, PAGE_SIZE, (void **)&dataptrs); 1083626738bSChristoph Hellwig 1093626738bSChristoph Hellwig for (i = 0; i < NDISKS - 1; i++) 1103626738bSChristoph Hellwig for (j = i + 1; j < NDISKS; j++) 111*2175395fSChristoph Hellwig test_recover(test, i, j); 1123626738bSChristoph Hellwig 113*2175395fSChristoph Hellwig if (!ta->gen->xor_syndrome) 114*2175395fSChristoph Hellwig return; 1153626738bSChristoph Hellwig 116*2175395fSChristoph Hellwig for (p1 = 0; p1 < NDISKS - 2; p1++) { 1173626738bSChristoph Hellwig for (p2 = p1; p2 < NDISKS - 2; p2++) { 1183626738bSChristoph Hellwig /* Simulate rmw run */ 119*2175395fSChristoph Hellwig ta->gen->xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 1203626738bSChristoph Hellwig (void **)&dataptrs); 1213626738bSChristoph Hellwig makedata(p1, p2); 122*2175395fSChristoph Hellwig ta->gen->xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 1233626738bSChristoph Hellwig (void **)&dataptrs); 1243626738bSChristoph Hellwig 1253626738bSChristoph Hellwig for (i = 0; i < NDISKS - 1; i++) 1263626738bSChristoph Hellwig for (j = i + 1; j < NDISKS; j++) 127*2175395fSChristoph Hellwig test_recover(test, i, j); 128*2175395fSChristoph Hellwig } 129*2175395fSChristoph Hellwig } 1303626738bSChristoph Hellwig } 1313626738bSChristoph Hellwig 132*2175395fSChristoph Hellwig static const void *raid6_gen_params(struct kunit *test, const void *prev, 133*2175395fSChristoph Hellwig char *desc) 134*2175395fSChristoph Hellwig { 135*2175395fSChristoph Hellwig if (!prev) { 136*2175395fSChristoph Hellwig memset(&args, 0, sizeof(args)); 137*2175395fSChristoph Hellwig next_algo: 138*2175395fSChristoph Hellwig args.recov_idx = 0; 139*2175395fSChristoph Hellwig args.gen = raid6_algo_find(args.gen_idx); 140*2175395fSChristoph Hellwig if (!args.gen) 141*2175395fSChristoph Hellwig return NULL; 1423626738bSChristoph Hellwig } 143*2175395fSChristoph Hellwig 144*2175395fSChristoph Hellwig if (args.recov) 145*2175395fSChristoph Hellwig args.recov_idx++; 146*2175395fSChristoph Hellwig args.recov = raid6_recov_algo_find(args.recov_idx); 147*2175395fSChristoph Hellwig if (!args.recov) { 148*2175395fSChristoph Hellwig args.gen_idx++; 149*2175395fSChristoph Hellwig goto next_algo; 1503626738bSChristoph Hellwig } 151*2175395fSChristoph Hellwig 152*2175395fSChristoph Hellwig snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gen=%s recov=%s", 153*2175395fSChristoph Hellwig args.gen->name, args.recov->name); 154*2175395fSChristoph Hellwig return &args; 1553626738bSChristoph Hellwig } 1563626738bSChristoph Hellwig 1573626738bSChristoph Hellwig static struct kunit_case raid6_test_cases[] = { 158*2175395fSChristoph Hellwig KUNIT_CASE_PARAM(raid6_test, raid6_gen_params), 1593626738bSChristoph Hellwig {}, 1603626738bSChristoph Hellwig }; 1613626738bSChristoph Hellwig 1623626738bSChristoph Hellwig static int raid6_suite_init(struct kunit_suite *suite) 1633626738bSChristoph Hellwig { 1643626738bSChristoph Hellwig prandom_seed_state(&rng, RAID6_KUNIT_SEED); 1653626738bSChristoph Hellwig makedata(0, NDISKS - 1); 1663626738bSChristoph Hellwig return 0; 1673626738bSChristoph Hellwig } 1683626738bSChristoph Hellwig 1693626738bSChristoph Hellwig static struct kunit_suite raid6_test_suite = { 1703626738bSChristoph Hellwig .name = "raid6", 1713626738bSChristoph Hellwig .test_cases = raid6_test_cases, 1723626738bSChristoph Hellwig .suite_init = raid6_suite_init, 1733626738bSChristoph Hellwig }; 1743626738bSChristoph Hellwig kunit_test_suite(raid6_test_suite); 1753626738bSChristoph Hellwig 1763626738bSChristoph Hellwig MODULE_DESCRIPTION("Unit test for the RAID P/Q library functions"); 1773626738bSChristoph Hellwig MODULE_LICENSE("GPL"); 178