1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* -*- linux-c -*- ------------------------------------------------------- * 3 * 4 * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved 5 * 6 * ----------------------------------------------------------------------- */ 7 8 /* 9 * raid6test.c 10 * 11 * Test RAID-6 recovery with various algorithms 12 */ 13 14 #include <stdlib.h> 15 #include <stdio.h> 16 #include <string.h> 17 #include <linux/raid/pq.h> 18 19 #define NDISKS 16 /* Including P and Q */ 20 21 const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 22 struct raid6_calls raid6_call; 23 24 char *dataptrs[NDISKS]; 25 char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 26 char recovi[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 27 char recovj[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 28 29 static void makedata(int start, int stop) 30 { 31 int i, j; 32 33 for (i = start; i <= stop; i++) { 34 for (j = 0; j < PAGE_SIZE; j++) 35 data[i][j] = rand(); 36 37 dataptrs[i] = data[i]; 38 } 39 } 40 41 static char disk_type(int d) 42 { 43 switch (d) { 44 case NDISKS-2: 45 return 'P'; 46 case NDISKS-1: 47 return 'Q'; 48 default: 49 return 'D'; 50 } 51 } 52 53 static int test_disks(int i, int j) 54 { 55 int erra, errb; 56 57 memset(recovi, 0xf0, PAGE_SIZE); 58 memset(recovj, 0xba, PAGE_SIZE); 59 60 dataptrs[i] = recovi; 61 dataptrs[j] = recovj; 62 63 raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs); 64 65 erra = memcmp(data[i], recovi, PAGE_SIZE); 66 errb = memcmp(data[j], recovj, PAGE_SIZE); 67 68 if (i < NDISKS-2 && j == NDISKS-1) { 69 /* We don't implement the DQ failure scenario, since it's 70 equivalent to a RAID-5 failure (XOR, then recompute Q) */ 71 erra = errb = 0; 72 } else { 73 printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n", 74 raid6_call.name, 75 i, disk_type(i), 76 j, disk_type(j), 77 (!erra && !errb) ? "OK" : 78 !erra ? "ERRB" : 79 !errb ? "ERRA" : "ERRAB"); 80 } 81 82 dataptrs[i] = data[i]; 83 dataptrs[j] = data[j]; 84 85 return erra || errb; 86 } 87 88 int main(int argc, char *argv[]) 89 { 90 const struct raid6_calls *const *algo; 91 const struct raid6_recov_calls *const *ra; 92 int i, j, p1, p2; 93 int err = 0; 94 95 makedata(0, NDISKS-1); 96 97 for (ra = raid6_recov_algos; *ra; ra++) { 98 if ((*ra)->valid && !(*ra)->valid()) 99 continue; 100 101 raid6_2data_recov = (*ra)->data2; 102 raid6_datap_recov = (*ra)->datap; 103 104 printf("using recovery %s\n", (*ra)->name); 105 106 for (algo = raid6_algos; *algo; algo++) { 107 if ((*algo)->valid && !(*algo)->valid()) 108 continue; 109 110 raid6_call = **algo; 111 112 /* Nuke syndromes */ 113 memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE); 114 115 /* Generate assumed good syndrome */ 116 raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, 117 (void **)&dataptrs); 118 119 for (i = 0; i < NDISKS-1; i++) 120 for (j = i+1; j < NDISKS; j++) 121 err += test_disks(i, j); 122 123 if (!raid6_call.xor_syndrome) 124 continue; 125 126 for (p1 = 0; p1 < NDISKS-2; p1++) 127 for (p2 = p1; p2 < NDISKS-2; p2++) { 128 129 /* Simulate rmw run */ 130 raid6_call.xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 131 (void **)&dataptrs); 132 makedata(p1, p2); 133 raid6_call.xor_syndrome(NDISKS, p1, p2, PAGE_SIZE, 134 (void **)&dataptrs); 135 136 for (i = 0; i < NDISKS-1; i++) 137 for (j = i+1; j < NDISKS; j++) 138 err += test_disks(i, j); 139 } 140 141 } 142 printf("\n"); 143 } 144 145 printf("\n"); 146 /* Pick the best algorithm test */ 147 raid6_select_algo(); 148 149 if (err) 150 printf("\n*** ERRORS FOUND ***\n"); 151 152 return err; 153 } 154