diff options
| author | Jim Kukunas <james.t.kukunas@linux.intel.com> | 2012-05-21 23:54:24 -0400 |
|---|---|---|
| committer | NeilBrown <neilb@suse.de> | 2012-05-21 23:54:24 -0400 |
| commit | 96e67703e71f4b3cc32b747dbb6158ec74d01e19 (patch) | |
| tree | 7abe4800c1827f5d3b3af42abeb19c8c3ac24df0 /lib | |
| parent | 2dbf708448c836754d25fe6108c5bfe1f5697c95 (diff) | |
lib/raid6: cleanup gen_syndrome function selection
Reorders functions in raid6_algos as well as the preference check
to reduce the number of functions tested on initialization.
Also, creates symmetry between choosing the gen_syndrome functions
and choosing the recovery functions.
Signed-off-by: Jim Kukunas <james.t.kukunas@linux.intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/raid6/algos.c | 104 |
1 files changed, 57 insertions, 47 deletions
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index 5a7f8022be13..589f5f50ad2e 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c | |||
| @@ -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,10 @@ 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 | 64 | NULL |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| @@ -86,7 +86,7 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = { | |||
| 86 | #define time_before(x, y) ((x) < (y)) | 86 | #define time_before(x, y) ((x) < (y)) |
| 87 | #endif | 87 | #endif |
| 88 | 88 | ||
| 89 | static inline void raid6_choose_recov(void) | 89 | static inline const struct raid6_recov_calls *raid6_choose_recov(void) |
| 90 | { | 90 | { |
| 91 | const struct raid6_recov_calls *const *algo; | 91 | const struct raid6_recov_calls *const *algo; |
| 92 | const struct raid6_recov_calls *best; | 92 | const struct raid6_recov_calls *best; |
| @@ -103,62 +103,38 @@ static inline void raid6_choose_recov(void) | |||
| 103 | printk("raid6: using %s recovery algorithm\n", best->name); | 103 | printk("raid6: using %s recovery algorithm\n", best->name); |
| 104 | } else | 104 | } else |
| 105 | printk("raid6: Yikes! No recovery algorithm found!\n"); | 105 | printk("raid6: Yikes! No recovery algorithm found!\n"); |
| 106 | } | ||
| 107 | |||
| 108 | 106 | ||
| 109 | /* Try to pick the best algorithm */ | 107 | return best; |
| 110 | /* This code uses the gfmul table as convenient data set to abuse */ | 108 | } |
| 111 | 109 | ||
| 112 | int __init raid6_select_algo(void) | 110 | static inline const struct raid6_calls *raid6_choose_gen( |
| 111 | void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks) | ||
| 113 | { | 112 | { |
| 114 | const struct raid6_calls * const * algo; | 113 | unsigned long perf, bestperf, j0, j1; |
| 115 | const struct raid6_calls * best; | 114 | const struct raid6_calls *const *algo; |
| 116 | char *syndromes; | 115 | const struct raid6_calls *best; |
| 117 | void *dptrs[(65536/PAGE_SIZE)+2]; | ||
| 118 | int i, disks; | ||
| 119 | unsigned long perf, bestperf; | ||
| 120 | int bestprefer; | ||
| 121 | unsigned long j0, j1; | ||
| 122 | |||
| 123 | disks = (65536/PAGE_SIZE)+2; | ||
| 124 | for ( i = 0 ; i < disks-2 ; i++ ) { | ||
| 125 | dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i; | ||
| 126 | } | ||
| 127 | |||
| 128 | /* Normal code - use a 2-page allocation to avoid D$ conflict */ | ||
| 129 | syndromes = (void *) __get_free_pages(GFP_KERNEL, 1); | ||
| 130 | |||
| 131 | if ( !syndromes ) { | ||
| 132 | printk("raid6: Yikes! No memory available.\n"); | ||
| 133 | return -ENOMEM; | ||
| 134 | } | ||
| 135 | |||
| 136 | dptrs[disks-2] = syndromes; | ||
| 137 | dptrs[disks-1] = syndromes + PAGE_SIZE; | ||
| 138 | 116 | ||
| 139 | 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; | ||
| 140 | 121 | ||
| 141 | for ( algo = raid6_algos ; *algo ; algo++ ) { | ||
| 142 | if ( !(*algo)->valid || (*algo)->valid() ) { | ||
| 143 | perf = 0; | 122 | perf = 0; |
| 144 | 123 | ||
| 145 | preempt_disable(); | 124 | preempt_disable(); |
| 146 | j0 = jiffies; | 125 | j0 = jiffies; |
| 147 | while ( (j1 = jiffies) == j0 ) | 126 | while ((j1 = jiffies) == j0) |
| 148 | cpu_relax(); | 127 | cpu_relax(); |
| 149 | while (time_before(jiffies, | 128 | while (time_before(jiffies, |
| 150 | j1 + (1<<RAID6_TIME_JIFFIES_LG2))) { | 129 | j1 + (1<<RAID6_TIME_JIFFIES_LG2))) { |
| 151 | (*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs); | 130 | (*algo)->gen_syndrome(disks, PAGE_SIZE, *dptrs); |
| 152 | perf++; | 131 | perf++; |
| 153 | } | 132 | } |
| 154 | preempt_enable(); | 133 | preempt_enable(); |
| 155 | 134 | ||
| 156 | if ( (*algo)->prefer > bestprefer || | 135 | if (perf > bestperf) { |
| 157 | ((*algo)->prefer == bestprefer && | ||
| 158 | perf > bestperf) ) { | ||
| 159 | best = *algo; | ||
| 160 | bestprefer = best->prefer; | ||
| 161 | bestperf = perf; | 136 | bestperf = perf; |
| 137 | best = *algo; | ||
| 162 | } | 138 | } |
| 163 | printk("raid6: %-8s %5ld MB/s\n", (*algo)->name, | 139 | printk("raid6: %-8s %5ld MB/s\n", (*algo)->name, |
| 164 | (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); | 140 | (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); |
| @@ -173,12 +149,46 @@ int __init raid6_select_algo(void) | |||
| 173 | } else | 149 | } else |
| 174 | printk("raid6: Yikes! No algorithm found!\n"); | 150 | printk("raid6: Yikes! No algorithm found!\n"); |
| 175 | 151 | ||
| 176 | free_pages((unsigned long)syndromes, 1); | 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); | ||
| 177 | 185 | ||
| 178 | /* select raid recover functions */ | 186 | /* select raid recover functions */ |
| 179 | raid6_choose_recov(); | 187 | rec_best = raid6_choose_recov(); |
| 188 | |||
| 189 | free_pages((unsigned long)syndromes, 1); | ||
| 180 | 190 | ||
| 181 | return best ? 0 : -EINVAL; | 191 | return gen_best && rec_best ? 0 : -EINVAL; |
| 182 | } | 192 | } |
| 183 | 193 | ||
| 184 | static void raid6_exit(void) | 194 | static void raid6_exit(void) |
