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) |
