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