Blame view

lib/raid6/algos.c 3.66 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>
056075c76   Paul Gortmaker   md: Add module.h ...
19
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #ifndef __KERNEL__
  #include <sys/mman.h>
d7e70ba45   H. Peter Anvin   [PATCH] RAID6 Alt...
22
  #include <stdio.h>
f701d589a   Dan Williams   md/raid6: move ra...
23
  #else
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
36
37
38
39
40
41
42
43
  const struct raid6_calls * const raid6_algos[] = {
  	&raid6_intx1,
  	&raid6_intx2,
  	&raid6_intx4,
  	&raid6_intx8,
  #if defined(__ia64__)
  	&raid6_intx16,
  	&raid6_intx32,
  #endif
ca5cd877a   Al Viro   x86 merge fallout...
44
  #if defined(__i386__) && !defined(__arch_um__)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
  	&raid6_mmxx1,
  	&raid6_mmxx2,
  	&raid6_sse1x1,
  	&raid6_sse1x2,
  	&raid6_sse2x1,
  	&raid6_sse2x2,
  #endif
ca5cd877a   Al Viro   x86 merge fallout...
52
  #if defined(__x86_64__) && !defined(__arch_um__)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  	&raid6_sse2x1,
  	&raid6_sse2x2,
  	&raid6_sse2x4,
  #endif
  #ifdef CONFIG_ALTIVEC
  	&raid6_altivec1,
  	&raid6_altivec2,
  	&raid6_altivec4,
  	&raid6_altivec8,
  #endif
  	NULL
  };
  
  #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...
71
  #define time_before(x, y) ((x) < (y))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  #endif
  
  /* 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 struct raid6_calls * const * algo;
  	const struct raid6_calls * best;
  	char *syndromes;
  	void *dptrs[(65536/PAGE_SIZE)+2];
  	int i, disks;
  	unsigned long perf, bestperf;
  	int bestprefer;
  	unsigned long j0, j1;
  
  	disks = (65536/PAGE_SIZE)+2;
  	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 ) {
  		printk("raid6: Yikes!  No memory available.
  ");
  		return -ENOMEM;
  	}
  
  	dptrs[disks-2] = syndromes;
  	dptrs[disks-1] = syndromes + PAGE_SIZE;
  
  	bestperf = 0;  bestprefer = 0;  best = NULL;
  
  	for ( algo = raid6_algos ; *algo ; algo++ ) {
  		if ( !(*algo)->valid || (*algo)->valid() ) {
  			perf = 0;
  
  			preempt_disable();
  			j0 = jiffies;
  			while ( (j1 = jiffies) == j0 )
  				cpu_relax();
62b0559aa   Julia Lawall   drivers/md: use t...
115
116
  			while (time_before(jiffies,
  					    j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  				(*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs);
  				perf++;
  			}
  			preempt_enable();
  
  			if ( (*algo)->prefer > bestprefer ||
  			     ((*algo)->prefer == bestprefer &&
  			      perf > bestperf) ) {
  				best = *algo;
  				bestprefer = best->prefer;
  				bestperf = perf;
  			}
  			printk("raid6: %-8s %5ld MB/s
  ", (*algo)->name,
  			       (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
  		}
  	}
a5d6839b7   Adrian Bunk   [PATCH] drivers/m...
134
  	if (best) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
  		printk("raid6: using algorithm %s (%ld MB/s)
  ",
  		       best->name,
  		       (bestperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
a5d6839b7   Adrian Bunk   [PATCH] drivers/m...
139
140
  		raid6_call = *best;
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  		printk("raid6: Yikes!  No algorithm found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
  	free_pages((unsigned long)syndromes, 1);
  
  	return best ? 0 : -EINVAL;
  }
f701d589a   Dan Williams   md/raid6: move ra...
147
148
149
150
151
152
153
154
155
  
  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...
156
  MODULE_DESCRIPTION("RAID6 Q-syndrome calculations");