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