xref: /linux/lib/raid/raid6/tests/raid6_kunit.c (revision 2175395f76c3eb3b19f1ce9be54d9dc9b0e4e61e)
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