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