Blame view

lib/raid6/algos.c 6.26 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /* -*- linux-c -*- ------------------------------------------------------- *
   *
   *   Copyright 2002 H. Peter Anvin - All Rights Reserved
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
93ed05e2a   Atsushi SAKAI   md: fix typo in F...
8
   *   Boston MA 02111-1307, USA; either version 2 of the License, or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
   *   (at your option) any later version; incorporated herein by reference.
   *
   * ----------------------------------------------------------------------- */
  
  /*
a8e026c78   NeilBrown   Further tidyup of...
14
   * raid6/algos.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
   *
   * Algorithm list and algorithm selection for RAID-6
   */
f701d589a   Dan Williams   md/raid6: move ra...
18
  #include <linux/raid/pq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #ifndef __KERNEL__
  #include <sys/mman.h>
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
21
  #include <stdio.h>
f701d589a   Dan Williams   md/raid6: move ra...
22
  #else
f674ef7b4   Jim Kukunas   lib/raid6: fix te...
23
  #include <linux/module.h>
d5302fe41   NeilBrown   Make lib/raid6/te...
24
  #include <linux/gfp.h>
f701d589a   Dan Williams   md/raid6: move ra...
25
26
27
28
29
  #if !RAID6_USE_EMPTY_ZERO_PAGE
  /* In .bss so it's zeroed */
  const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
  EXPORT_SYMBOL(raid6_empty_zero_page);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
  #endif
  
  struct raid6_calls raid6_call;
f701d589a   Dan Williams   md/raid6: move ra...
33
  EXPORT_SYMBOL_GPL(raid6_call);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  const struct raid6_calls * const raid6_algos[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
  #if defined(__ia64__)
  	&raid6_intx16,
  	&raid6_intx32,
  #endif
ca5cd877a   Al Viro   x86 merge fallout...
40
  #if defined(__i386__) && !defined(__arch_um__)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
  	&raid6_mmxx1,
  	&raid6_mmxx2,
  	&raid6_sse1x1,
  	&raid6_sse1x2,
  	&raid6_sse2x1,
  	&raid6_sse2x2,
2c935842b   Yuanhan Liu   lib/raid6: Add AV...
47
48
49
50
  #ifdef CONFIG_AS_AVX2
  	&raid6_avx2x1,
  	&raid6_avx2x2,
  #endif
e0a491c12   Gayatri Kammela   lib/raid6: Add AV...
51
52
53
54
  #ifdef CONFIG_AS_AVX512
  	&raid6_avx512x1,
  	&raid6_avx512x2,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  #endif
ca5cd877a   Al Viro   x86 merge fallout...
56
  #if defined(__x86_64__) && !defined(__arch_um__)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  	&raid6_sse2x1,
  	&raid6_sse2x2,
  	&raid6_sse2x4,
2c935842b   Yuanhan Liu   lib/raid6: Add AV...
60
61
62
63
64
  #ifdef CONFIG_AS_AVX2
  	&raid6_avx2x1,
  	&raid6_avx2x2,
  	&raid6_avx2x4,
  #endif
e0a491c12   Gayatri Kammela   lib/raid6: Add AV...
65
66
67
68
69
  #ifdef CONFIG_AS_AVX512
  	&raid6_avx512x1,
  	&raid6_avx512x2,
  	&raid6_avx512x4,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
  #endif
  #ifdef CONFIG_ALTIVEC
  	&raid6_altivec1,
  	&raid6_altivec2,
  	&raid6_altivec4,
  	&raid6_altivec8,
  #endif
ae77cbc1e   Ken Steele   RAID: add tilegx ...
77
78
79
  #if defined(CONFIG_TILEGX)
  	&raid6_tilegx8,
  #endif
474fd6e80   Martin Schwidefsky   RAID/s390: add SI...
80
81
82
  #if defined(CONFIG_S390)
  	&raid6_s390vx8,
  #endif
96e67703e   Jim Kukunas   lib/raid6: cleanu...
83
84
85
86
  	&raid6_intx1,
  	&raid6_intx2,
  	&raid6_intx4,
  	&raid6_intx8,
7d11965dd   Ard Biesheuvel   lib/raid6: add AR...
87
88
89
90
91
92
  #ifdef CONFIG_KERNEL_MODE_NEON
  	&raid6_neonx1,
  	&raid6_neonx2,
  	&raid6_neonx4,
  	&raid6_neonx8,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  	NULL
  };
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
95
96
97
98
99
100
101
  void (*raid6_2data_recov)(int, size_t, int, int, void **);
  EXPORT_SYMBOL_GPL(raid6_2data_recov);
  
  void (*raid6_datap_recov)(int, size_t, int, void **);
  EXPORT_SYMBOL_GPL(raid6_datap_recov);
  
  const struct raid6_recov_calls *const raid6_recov_algos[] = {
13c520b29   Gayatri Kammela   lib/raid6: Add AV...
102
103
104
  #ifdef CONFIG_AS_AVX512
  	&raid6_recov_avx512,
  #endif
7056741fd   Jim Kukunas   lib/raid6: Add AV...
105
106
107
  #ifdef CONFIG_AS_AVX2
  	&raid6_recov_avx2,
  #endif
75aaf4c3e   Jan Beulich   x86/raid6: correc...
108
  #ifdef CONFIG_AS_SSSE3
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
109
110
  	&raid6_recov_ssse3,
  #endif
f5b55fa1f   Martin Schwidefsky   RAID/s390: provid...
111
112
113
  #ifdef CONFIG_S390
  	&raid6_recov_s390xc,
  #endif
6ec4e2514   Ard Biesheuvel   md/raid6: impleme...
114
115
116
  #if defined(CONFIG_KERNEL_MODE_NEON)
  	&raid6_recov_neon,
  #endif
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
117
118
119
  	&raid6_recov_intx1,
  	NULL
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
  #ifdef __KERNEL__
  #define RAID6_TIME_JIFFIES_LG2	4
  #else
  /* Need more time to be stable in userspace */
  #define RAID6_TIME_JIFFIES_LG2	9
f701d589a   Dan Williams   md/raid6: move ra...
125
  #define time_before(x, y) ((x) < (y))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  #endif
96e67703e   Jim Kukunas   lib/raid6: cleanu...
127
  static inline const struct raid6_recov_calls *raid6_choose_recov(void)
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
128
129
130
131
132
133
134
135
136
137
138
139
  {
  	const struct raid6_recov_calls *const *algo;
  	const struct raid6_recov_calls *best;
  
  	for (best = NULL, algo = raid6_recov_algos; *algo; algo++)
  		if (!best || (*algo)->priority > best->priority)
  			if (!(*algo)->valid || (*algo)->valid())
  				best = *algo;
  
  	if (best) {
  		raid6_2data_recov = best->data2;
  		raid6_datap_recov = best->datap;
b395f75ea   Anton Blanchard   lib/raid6: Add lo...
140
141
  		pr_info("raid6: using %s recovery algorithm
  ", best->name);
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
142
  	} else
b395f75ea   Anton Blanchard   lib/raid6: Add lo...
143
144
  		pr_err("raid6: Yikes! No recovery algorithm found!
  ");
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
145

96e67703e   Jim Kukunas   lib/raid6: cleanu...
146
147
  	return best;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

96e67703e   Jim Kukunas   lib/raid6: cleanu...
149
150
  static inline const struct raid6_calls *raid6_choose_gen(
  	void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  {
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
152
153
  	unsigned long perf, bestgenperf, bestxorperf, j0, j1;
  	int start = (disks>>1)-1, stop = disks-3;	/* work on the second half of the disks */
96e67703e   Jim Kukunas   lib/raid6: cleanu...
154
155
  	const struct raid6_calls *const *algo;
  	const struct raid6_calls *best;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156

fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
157
  	for (bestgenperf = 0, bestxorperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) {
96e67703e   Jim Kukunas   lib/raid6: cleanu...
158
159
160
  		if (!best || (*algo)->prefer >= best->prefer) {
  			if ((*algo)->valid && !(*algo)->valid())
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
  			perf = 0;
  
  			preempt_disable();
  			j0 = jiffies;
96e67703e   Jim Kukunas   lib/raid6: cleanu...
166
  			while ((j1 = jiffies) == j0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  				cpu_relax();
62b0559aa   Julia Lawall   drivers/md: use t...
168
169
  			while (time_before(jiffies,
  					    j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
96e67703e   Jim Kukunas   lib/raid6: cleanu...
170
  				(*algo)->gen_syndrome(disks, PAGE_SIZE, *dptrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
  				perf++;
  			}
  			preempt_enable();
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
174
175
  			if (perf > bestgenperf) {
  				bestgenperf = perf;
96e67703e   Jim Kukunas   lib/raid6: cleanu...
176
  				best = *algo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  			}
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
178
179
  			pr_info("raid6: %-8s gen() %5ld MB/s
  ", (*algo)->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  			       (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  
  			if (!(*algo)->xor_syndrome)
  				continue;
  
  			perf = 0;
  
  			preempt_disable();
  			j0 = jiffies;
  			while ((j1 = jiffies) == j0)
  				cpu_relax();
  			while (time_before(jiffies,
  					    j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
  				(*algo)->xor_syndrome(disks, start, stop,
  						      PAGE_SIZE, *dptrs);
  				perf++;
  			}
  			preempt_enable();
  
  			if (best == *algo)
  				bestxorperf = perf;
  
  			pr_info("raid6: %-8s xor() %5ld MB/s
  ", (*algo)->name,
  				(perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2+1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  		}
  	}
a5d6839b7   Adrian Bunk   [PATCH] drivers/m...
207
  	if (best) {
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
208
209
  		pr_info("raid6: using algorithm %s gen() %ld MB/s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  		       best->name,
fe5cbc6e0   Markus Stockhausen   md/raid6 algorith...
211
212
213
214
215
  		       (bestgenperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
  		if (best->xor_syndrome)
  			pr_info("raid6: .... xor() %ld MB/s, rmw enabled
  ",
  			       (bestxorperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2+1));
a5d6839b7   Adrian Bunk   [PATCH] drivers/m...
216
217
  		raid6_call = *best;
  	} else
b395f75ea   Anton Blanchard   lib/raid6: Add lo...
218
219
  		pr_err("raid6: Yikes!  No algorithm found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

96e67703e   Jim Kukunas   lib/raid6: cleanu...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  	return best;
  }
  
  
  /* Try to pick the best algorithm */
  /* This code uses the gfmul table as convenient data set to abuse */
  
  int __init raid6_select_algo(void)
  {
  	const int disks = (65536/PAGE_SIZE)+2;
  
  	const struct raid6_calls *gen_best;
  	const struct raid6_recov_calls *rec_best;
  	char *syndromes;
  	void *dptrs[(65536/PAGE_SIZE)+2];
  	int i;
  
  	for (i = 0; i < disks-2; i++)
  		dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i;
  
  	/* Normal code - use a 2-page allocation to avoid D$ conflict */
  	syndromes = (void *) __get_free_pages(GFP_KERNEL, 1);
  
  	if (!syndromes) {
b395f75ea   Anton Blanchard   lib/raid6: Add lo...
245
246
  		pr_err("raid6: Yikes!  No memory available.
  ");
96e67703e   Jim Kukunas   lib/raid6: cleanu...
247
248
249
250
251
252
253
254
  		return -ENOMEM;
  	}
  
  	dptrs[disks-2] = syndromes;
  	dptrs[disks-1] = syndromes + PAGE_SIZE;
  
  	/* select raid gen_syndrome function */
  	gen_best = raid6_choose_gen(&dptrs, disks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255

048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
256
  	/* select raid recover functions */
96e67703e   Jim Kukunas   lib/raid6: cleanu...
257
258
259
  	rec_best = raid6_choose_recov();
  
  	free_pages((unsigned long)syndromes, 1);
048a8b8c8   Jim Kukunas   lib/raid6: Add SS...
260

96e67703e   Jim Kukunas   lib/raid6: cleanu...
261
  	return gen_best && rec_best ? 0 : -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  }
f701d589a   Dan Williams   md/raid6: move ra...
263
264
265
266
267
268
269
270
271
  
  static void raid6_exit(void)
  {
  	do { } while (0);
  }
  
  subsys_initcall(raid6_select_algo);
  module_exit(raid6_exit);
  MODULE_LICENSE("GPL");
0efb9e619   NeilBrown   md: add MODULE_DE...
272
  MODULE_DESCRIPTION("RAID6 Q-syndrome calculations");