diff options
Diffstat (limited to 'lib/raid6/algos.c')
-rw-r--r-- | lib/raid6/algos.c | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index 8b02f60ffc86..589f5f50ad2e 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c | |||
@@ -17,11 +17,11 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/raid/pq.h> | 19 | #include <linux/raid/pq.h> |
20 | #include <linux/module.h> | ||
21 | #ifndef __KERNEL__ | 20 | #ifndef __KERNEL__ |
22 | #include <sys/mman.h> | 21 | #include <sys/mman.h> |
23 | #include <stdio.h> | 22 | #include <stdio.h> |
24 | #else | 23 | #else |
24 | #include <linux/module.h> | ||
25 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
26 | #if !RAID6_USE_EMPTY_ZERO_PAGE | 26 | #if !RAID6_USE_EMPTY_ZERO_PAGE |
27 | /* In .bss so it's zeroed */ | 27 | /* In .bss so it's zeroed */ |
@@ -34,10 +34,6 @@ struct raid6_calls raid6_call; | |||
34 | EXPORT_SYMBOL_GPL(raid6_call); | 34 | EXPORT_SYMBOL_GPL(raid6_call); |
35 | 35 | ||
36 | const struct raid6_calls * const raid6_algos[] = { | 36 | const struct raid6_calls * const raid6_algos[] = { |
37 | &raid6_intx1, | ||
38 | &raid6_intx2, | ||
39 | &raid6_intx4, | ||
40 | &raid6_intx8, | ||
41 | #if defined(__ia64__) | 37 | #if defined(__ia64__) |
42 | &raid6_intx16, | 38 | &raid6_intx16, |
43 | &raid6_intx32, | 39 | &raid6_intx32, |
@@ -61,6 +57,24 @@ const struct raid6_calls * const raid6_algos[] = { | |||
61 | &raid6_altivec4, | 57 | &raid6_altivec4, |
62 | &raid6_altivec8, | 58 | &raid6_altivec8, |
63 | #endif | 59 | #endif |
60 | &raid6_intx1, | ||
61 | &raid6_intx2, | ||
62 | &raid6_intx4, | ||
63 | &raid6_intx8, | ||
64 | NULL | ||
65 | }; | ||
66 | |||
67 | void (*raid6_2data_recov)(int, size_t, int, int, void **); | ||
68 | EXPORT_SYMBOL_GPL(raid6_2data_recov); | ||
69 | |||
70 | void (*raid6_datap_recov)(int, size_t, int, void **); | ||
71 | EXPORT_SYMBOL_GPL(raid6_datap_recov); | ||
72 | |||
73 | const struct raid6_recov_calls *const raid6_recov_algos[] = { | ||
74 | #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) | ||
75 | &raid6_recov_ssse3, | ||
76 | #endif | ||
77 | &raid6_recov_intx1, | ||
64 | NULL | 78 | NULL |
65 | }; | 79 | }; |
66 | 80 | ||
@@ -72,59 +86,55 @@ const struct raid6_calls * const raid6_algos[] = { | |||
72 | #define time_before(x, y) ((x) < (y)) | 86 | #define time_before(x, y) ((x) < (y)) |
73 | #endif | 87 | #endif |
74 | 88 | ||
75 | /* Try to pick the best algorithm */ | 89 | static inline const struct raid6_recov_calls *raid6_choose_recov(void) |
76 | /* This code uses the gfmul table as convenient data set to abuse */ | ||
77 | |||
78 | int __init raid6_select_algo(void) | ||
79 | { | 90 | { |
80 | const struct raid6_calls * const * algo; | 91 | const struct raid6_recov_calls *const *algo; |
81 | const struct raid6_calls * best; | 92 | const struct raid6_recov_calls *best; |
82 | char *syndromes; | ||
83 | void *dptrs[(65536/PAGE_SIZE)+2]; | ||
84 | int i, disks; | ||
85 | unsigned long perf, bestperf; | ||
86 | int bestprefer; | ||
87 | unsigned long j0, j1; | ||
88 | 93 | ||
89 | disks = (65536/PAGE_SIZE)+2; | 94 | for (best = NULL, algo = raid6_recov_algos; *algo; algo++) |
90 | for ( i = 0 ; i < disks-2 ; i++ ) { | 95 | if (!best || (*algo)->priority > best->priority) |
91 | dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i; | 96 | if (!(*algo)->valid || (*algo)->valid()) |
92 | } | 97 | best = *algo; |
93 | 98 | ||
94 | /* Normal code - use a 2-page allocation to avoid D$ conflict */ | 99 | if (best) { |
95 | syndromes = (void *) __get_free_pages(GFP_KERNEL, 1); | 100 | raid6_2data_recov = best->data2; |
101 | raid6_datap_recov = best->datap; | ||
96 | 102 | ||
97 | if ( !syndromes ) { | 103 | printk("raid6: using %s recovery algorithm\n", best->name); |
98 | printk("raid6: Yikes! No memory available.\n"); | 104 | } else |
99 | return -ENOMEM; | 105 | printk("raid6: Yikes! No recovery algorithm found!\n"); |
100 | } | ||
101 | 106 | ||
102 | dptrs[disks-2] = syndromes; | 107 | return best; |
103 | dptrs[disks-1] = syndromes + PAGE_SIZE; | 108 | } |
109 | |||
110 | static inline const struct raid6_calls *raid6_choose_gen( | ||
111 | void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks) | ||
112 | { | ||
113 | unsigned long perf, bestperf, j0, j1; | ||
114 | const struct raid6_calls *const *algo; | ||
115 | const struct raid6_calls *best; | ||
104 | 116 | ||
105 | bestperf = 0; bestprefer = 0; best = NULL; | 117 | for (bestperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) { |
118 | if (!best || (*algo)->prefer >= best->prefer) { | ||
119 | if ((*algo)->valid && !(*algo)->valid()) | ||
120 | continue; | ||
106 | 121 | ||
107 | for ( algo = raid6_algos ; *algo ; algo++ ) { | ||
108 | if ( !(*algo)->valid || (*algo)->valid() ) { | ||
109 | perf = 0; | 122 | perf = 0; |
110 | 123 | ||
111 | preempt_disable(); | 124 | preempt_disable(); |
112 | j0 = jiffies; | 125 | j0 = jiffies; |
113 | while ( (j1 = jiffies) == j0 ) | 126 | while ((j1 = jiffies) == j0) |
114 | cpu_relax(); | 127 | cpu_relax(); |
115 | while (time_before(jiffies, | 128 | while (time_before(jiffies, |
116 | j1 + (1<<RAID6_TIME_JIFFIES_LG2))) { | 129 | j1 + (1<<RAID6_TIME_JIFFIES_LG2))) { |
117 | (*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs); | 130 | (*algo)->gen_syndrome(disks, PAGE_SIZE, *dptrs); |
118 | perf++; | 131 | perf++; |
119 | } | 132 | } |
120 | preempt_enable(); | 133 | preempt_enable(); |
121 | 134 | ||
122 | if ( (*algo)->prefer > bestprefer || | 135 | if (perf > bestperf) { |
123 | ((*algo)->prefer == bestprefer && | ||
124 | perf > bestperf) ) { | ||
125 | best = *algo; | ||
126 | bestprefer = best->prefer; | ||
127 | bestperf = perf; | 136 | bestperf = perf; |
137 | best = *algo; | ||
128 | } | 138 | } |
129 | printk("raid6: %-8s %5ld MB/s\n", (*algo)->name, | 139 | printk("raid6: %-8s %5ld MB/s\n", (*algo)->name, |
130 | (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); | 140 | (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); |
@@ -139,9 +149,46 @@ int __init raid6_select_algo(void) | |||
139 | } else | 149 | } else |
140 | printk("raid6: Yikes! No algorithm found!\n"); | 150 | printk("raid6: Yikes! No algorithm found!\n"); |
141 | 151 | ||
152 | return best; | ||
153 | } | ||
154 | |||
155 | |||
156 | /* Try to pick the best algorithm */ | ||
157 | /* This code uses the gfmul table as convenient data set to abuse */ | ||
158 | |||
159 | int __init raid6_select_algo(void) | ||
160 | { | ||
161 | const int disks = (65536/PAGE_SIZE)+2; | ||
162 | |||
163 | const struct raid6_calls *gen_best; | ||
164 | const struct raid6_recov_calls *rec_best; | ||
165 | char *syndromes; | ||
166 | void *dptrs[(65536/PAGE_SIZE)+2]; | ||
167 | int i; | ||
168 | |||
169 | for (i = 0; i < disks-2; i++) | ||
170 | dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i; | ||
171 | |||
172 | /* Normal code - use a 2-page allocation to avoid D$ conflict */ | ||
173 | syndromes = (void *) __get_free_pages(GFP_KERNEL, 1); | ||
174 | |||
175 | if (!syndromes) { | ||
176 | printk("raid6: Yikes! No memory available.\n"); | ||
177 | return -ENOMEM; | ||
178 | } | ||
179 | |||
180 | dptrs[disks-2] = syndromes; | ||
181 | dptrs[disks-1] = syndromes + PAGE_SIZE; | ||
182 | |||
183 | /* select raid gen_syndrome function */ | ||
184 | gen_best = raid6_choose_gen(&dptrs, disks); | ||
185 | |||
186 | /* select raid recover functions */ | ||
187 | rec_best = raid6_choose_recov(); | ||
188 | |||
142 | free_pages((unsigned long)syndromes, 1); | 189 | free_pages((unsigned long)syndromes, 1); |
143 | 190 | ||
144 | return best ? 0 : -EINVAL; | 191 | return gen_best && rec_best ? 0 : -EINVAL; |
145 | } | 192 | } |
146 | 193 | ||
147 | static void raid6_exit(void) | 194 | static void raid6_exit(void) |