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> 10*769d603fSChristoph 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 243626738bSChristoph Hellwig static void makedata(int start, int stop) 253626738bSChristoph Hellwig { 263626738bSChristoph Hellwig int i; 273626738bSChristoph Hellwig 283626738bSChristoph Hellwig for (i = start; i <= stop; i++) { 293626738bSChristoph Hellwig prandom_bytes_state(&rng, data[i], PAGE_SIZE); 303626738bSChristoph Hellwig dataptrs[i] = data[i]; 313626738bSChristoph Hellwig } 323626738bSChristoph Hellwig } 333626738bSChristoph Hellwig 343626738bSChristoph Hellwig static char member_type(int d) 353626738bSChristoph Hellwig { 363626738bSChristoph Hellwig switch (d) { 373626738bSChristoph Hellwig case NDISKS-2: 383626738bSChristoph Hellwig return 'P'; 393626738bSChristoph Hellwig case NDISKS-1: 403626738bSChristoph Hellwig return 'Q'; 413626738bSChristoph Hellwig default: 423626738bSChristoph Hellwig return 'D'; 433626738bSChristoph Hellwig } 443626738bSChristoph Hellwig } 453626738bSChristoph Hellwig 463626738bSChristoph Hellwig static void test_disks(struct kunit *test, const struct raid6_calls *calls, 473626738bSChristoph Hellwig const struct raid6_recov_calls *ra, int faila, int failb) 483626738bSChristoph Hellwig { 493626738bSChristoph Hellwig memset(recovi, 0xf0, PAGE_SIZE); 503626738bSChristoph Hellwig memset(recovj, 0xba, PAGE_SIZE); 513626738bSChristoph Hellwig 523626738bSChristoph Hellwig dataptrs[faila] = recovi; 533626738bSChristoph Hellwig dataptrs[failb] = recovj; 543626738bSChristoph Hellwig 553626738bSChristoph Hellwig if (failb == NDISKS - 1) { 563626738bSChristoph Hellwig /* 573626738bSChristoph Hellwig * We don't implement the data+Q failure scenario, since it 583626738bSChristoph Hellwig * is equivalent to a RAID-5 failure (XOR, then recompute Q). 593626738bSChristoph Hellwig */ 603626738bSChristoph Hellwig if (faila != NDISKS - 2) 613626738bSChristoph Hellwig goto skip; 623626738bSChristoph Hellwig 633626738bSChristoph Hellwig /* P+Q failure. Just rebuild the syndrome. */ 643626738bSChristoph Hellwig calls->gen_syndrome(NDISKS, PAGE_SIZE, dataptrs); 653626738bSChristoph Hellwig } else if (failb == NDISKS - 2) { 663626738bSChristoph Hellwig /* data+P failure. */ 673626738bSChristoph Hellwig ra->datap(NDISKS, PAGE_SIZE, faila, dataptrs); 683626738bSChristoph Hellwig } else { 693626738bSChristoph Hellwig /* data+data failure. */ 703626738bSChristoph Hellwig ra->data2(NDISKS, PAGE_SIZE, faila, failb, dataptrs); 713626738bSChristoph Hellwig } 723626738bSChristoph Hellwig 733626738bSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, data[faila], recovi, PAGE_SIZE, 743626738bSChristoph Hellwig "algo=%-8s/%-8s faila miscompared: %3d[%c] (failb=%3d[%c])\n", 753626738bSChristoph Hellwig calls->name, ra->name, 763626738bSChristoph Hellwig faila, member_type(faila), 773626738bSChristoph Hellwig failb, member_type(failb)); 783626738bSChristoph Hellwig KUNIT_EXPECT_MEMEQ_MSG(test, data[failb], recovj, PAGE_SIZE, 793626738bSChristoph Hellwig "algo=%-8s/%-8s failb miscompared: %3d[%c] (faila=%3d[%c])\n", 803626738bSChristoph Hellwig calls->name, ra->name, 813626738bSChristoph Hellwig failb, member_type(failb), 823626738bSChristoph Hellwig faila, member_type(faila)); 833626738bSChristoph Hellwig 843626738bSChristoph Hellwig skip: 853626738bSChristoph Hellwig dataptrs[faila] = data[faila]; 863626738bSChristoph Hellwig dataptrs[failb] = data[failb]; 873626738bSChristoph Hellwig } 883626738bSChristoph Hellwig 893626738bSChristoph Hellwig static void raid6_test(struct kunit *test) 903626738bSChristoph Hellwig { 913626738bSChristoph Hellwig const struct raid6_calls *const *algo; 923626738bSChristoph Hellwig const struct raid6_recov_calls *const *ra; 933626738bSChristoph Hellwig int i, j, p1, p2; 943626738bSChristoph Hellwig 953626738bSChristoph Hellwig for (ra = raid6_recov_algos; *ra; ra++) { 963626738bSChristoph Hellwig if ((*ra)->valid && !(*ra)->valid()) 973626738bSChristoph Hellwig continue; 983626738bSChristoph Hellwig 993626738bSChristoph Hellwig for (algo = raid6_algos; *algo; algo++) { 1003626738bSChristoph Hellwig const struct raid6_calls *calls = *algo; 1013626738bSChristoph Hellwig 1023626738bSChristoph Hellwig if (calls->valid && !calls->valid()) 1033626738bSChristoph Hellwig continue; 1043626738bSChristoph Hellwig 1053626738bSChristoph Hellwig /* Nuke syndromes */ 1063626738bSChristoph Hellwig memset(data[NDISKS - 2], 0xee, PAGE_SIZE); 1073626738bSChristoph Hellwig memset(data[NDISKS - 1], 0xee, PAGE_SIZE); 1083626738bSChristoph Hellwig 1093626738bSChristoph Hellwig /* Generate assumed good syndrome */ 1103626738bSChristoph Hellwig calls->gen_syndrome(NDISKS, PAGE_SIZE, 1113626738bSChristoph Hellwig (void **)&dataptrs); 1123626738bSChristoph Hellwig 1133626738bSChristoph Hellwig for (i = 0; i < NDISKS-1; i++) 1143626738bSChristoph Hellwig for (j = i+1; j < NDISKS; j++) 1153626738bSChristoph Hellwig test_disks(test, calls, *ra, i, j); 1163626738bSChristoph Hellwig 1173626738bSChristoph Hellwig if (!calls->xor_syndrome) 1183626738bSChristoph Hellwig continue; 1193626738bSChristoph Hellwig 1203626738bSChristoph Hellwig for (p1 = 0; p1 < NDISKS-2; p1++) 1213626738bSChristoph Hellwig for (p2 = p1; p2 < NDISKS-2; p2++) { 1223626738bSChristoph Hellwig 1233626738bSChristoph Hellwig /* Simulate rmw run */ 1243626738bSChristoph Hellwig calls->xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 1253626738bSChristoph Hellwig (void **)&dataptrs); 1263626738bSChristoph Hellwig makedata(p1, p2); 1273626738bSChristoph Hellwig calls->xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 1283626738bSChristoph Hellwig (void **)&dataptrs); 1293626738bSChristoph Hellwig 1303626738bSChristoph Hellwig for (i = 0; i < NDISKS-1; i++) 1313626738bSChristoph Hellwig for (j = i+1; j < NDISKS; j++) 1323626738bSChristoph Hellwig test_disks(test, calls, 1333626738bSChristoph Hellwig *ra, i, j); 1343626738bSChristoph Hellwig } 1353626738bSChristoph Hellwig 1363626738bSChristoph Hellwig } 1373626738bSChristoph Hellwig } 1383626738bSChristoph Hellwig } 1393626738bSChristoph Hellwig 1403626738bSChristoph Hellwig static struct kunit_case raid6_test_cases[] = { 1413626738bSChristoph Hellwig KUNIT_CASE(raid6_test), 1423626738bSChristoph Hellwig {}, 1433626738bSChristoph Hellwig }; 1443626738bSChristoph Hellwig 1453626738bSChristoph Hellwig static int raid6_suite_init(struct kunit_suite *suite) 1463626738bSChristoph Hellwig { 1473626738bSChristoph Hellwig prandom_seed_state(&rng, RAID6_KUNIT_SEED); 1483626738bSChristoph Hellwig makedata(0, NDISKS - 1); 1493626738bSChristoph Hellwig return 0; 1503626738bSChristoph Hellwig } 1513626738bSChristoph Hellwig 1523626738bSChristoph Hellwig static struct kunit_suite raid6_test_suite = { 1533626738bSChristoph Hellwig .name = "raid6", 1543626738bSChristoph Hellwig .test_cases = raid6_test_cases, 1553626738bSChristoph Hellwig .suite_init = raid6_suite_init, 1563626738bSChristoph Hellwig }; 1573626738bSChristoph Hellwig kunit_test_suite(raid6_test_suite); 1583626738bSChristoph Hellwig 1593626738bSChristoph Hellwig MODULE_DESCRIPTION("Unit test for the RAID P/Q library functions"); 1603626738bSChristoph Hellwig MODULE_LICENSE("GPL"); 161