]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From 99c0fb5f92828ae96909d390f2df137b89093b37 Mon Sep 17 00:00:00 2001 |
2 | From: NeilBrown <neilb@suse.de> | |
3 | Date: Tue, 31 Mar 2009 14:39:38 +1100 | |
4 | Subject: [PATCH] md/raid5: Add support for new layouts for raid5 and raid6. | |
5 | ||
6 | DDF uses different layouts for P and Q blocks than current md/raid6 | |
7 | so add those that are missing. | |
8 | Also add support for RAID6 layouts that are identical to various | |
9 | raid5 layouts with the simple addition of one device to hold all of | |
10 | the 'Q' blocks. | |
11 | Finally add 'raid5' layouts to match raid4. | |
12 | These last to will allow online level conversion. | |
13 | ||
14 | Note that this does not provide correct support for DDF/raid6 yet | |
15 | as the order in which data blocks are summed to produce the Q block | |
16 | is significant and different between current md code and DDF | |
17 | requirements. | |
18 | ||
19 | Signed-off-by: NeilBrown <neilb@suse.de> | |
20 | --- | |
21 | drivers/md/raid5.c | 151 ++++++++++++++++++++++++++++++++++++++++----- | |
22 | include/linux/raid/raid5.h | 61 ++++++++++++++++-- | |
23 | 2 files changed, 193 insertions(+), 19 deletions(-) | |
24 | ||
25 | --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c | |
26 | +++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c | |
27 | @@ -1100,7 +1100,7 @@ static void shrink_stripes(raid5_conf_t | |
28 | ||
29 | static void raid5_end_read_request(struct bio * bi, int error) | |
30 | { | |
31 | - struct stripe_head *sh = bi->bi_private; | |
32 | + struct stripe_head *sh = bi->bi_private; | |
33 | raid5_conf_t *conf = sh->raid_conf; | |
34 | int disks = sh->disks, i; | |
35 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | |
36 | @@ -1182,7 +1182,7 @@ static void raid5_end_read_request(struc | |
37 | ||
38 | static void raid5_end_write_request (struct bio *bi, int error) | |
39 | { | |
40 | - struct stripe_head *sh = bi->bi_private; | |
41 | + struct stripe_head *sh = bi->bi_private; | |
42 | raid5_conf_t *conf = sh->raid_conf; | |
43 | int disks = sh->disks, i; | |
44 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | |
45 | @@ -1322,20 +1322,27 @@ static sector_t raid5_compute_sector(rai | |
46 | pd_idx = stripe % raid_disks; | |
47 | *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; | |
48 | break; | |
49 | + case ALGORITHM_PARITY_0: | |
50 | + pd_idx = 0; | |
51 | + (*dd_idx)++; | |
52 | + break; | |
53 | + case ALGORITHM_PARITY_N: | |
54 | + pd_idx = data_disks; | |
55 | + break; | |
56 | default: | |
57 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", | |
58 | conf->algorithm); | |
59 | + BUG(); | |
60 | } | |
61 | break; | |
62 | case 6: | |
63 | ||
64 | - /**** FIX THIS ****/ | |
65 | switch (conf->algorithm) { | |
66 | case ALGORITHM_LEFT_ASYMMETRIC: | |
67 | pd_idx = raid_disks - 1 - (stripe % raid_disks); | |
68 | qd_idx = pd_idx + 1; | |
69 | if (pd_idx == raid_disks-1) { | |
70 | - (*dd_idx)++; /* Q D D D P */ | |
71 | + (*dd_idx)++; /* Q D D D P */ | |
72 | qd_idx = 0; | |
73 | } else if (*dd_idx >= pd_idx) | |
74 | (*dd_idx) += 2; /* D D P Q D */ | |
75 | @@ -1344,7 +1351,7 @@ static sector_t raid5_compute_sector(rai | |
76 | pd_idx = stripe % raid_disks; | |
77 | qd_idx = pd_idx + 1; | |
78 | if (pd_idx == raid_disks-1) { | |
79 | - (*dd_idx)++; /* Q D D D P */ | |
80 | + (*dd_idx)++; /* Q D D D P */ | |
81 | qd_idx = 0; | |
82 | } else if (*dd_idx >= pd_idx) | |
83 | (*dd_idx) += 2; /* D D P Q D */ | |
84 | @@ -1359,9 +1366,89 @@ static sector_t raid5_compute_sector(rai | |
85 | qd_idx = (pd_idx + 1) % raid_disks; | |
86 | *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; | |
87 | break; | |
88 | + | |
89 | + case ALGORITHM_PARITY_0: | |
90 | + pd_idx = 0; | |
91 | + qd_idx = 1; | |
92 | + (*dd_idx) += 2; | |
93 | + break; | |
94 | + case ALGORITHM_PARITY_N: | |
95 | + pd_idx = data_disks; | |
96 | + qd_idx = data_disks + 1; | |
97 | + break; | |
98 | + | |
99 | + case ALGORITHM_ROTATING_ZERO_RESTART: | |
100 | + /* Exactly the same as RIGHT_ASYMMETRIC, but or | |
101 | + * of blocks for computing Q is different. | |
102 | + */ | |
103 | + pd_idx = stripe % raid_disks; | |
104 | + qd_idx = pd_idx + 1; | |
105 | + if (pd_idx == raid_disks-1) { | |
106 | + (*dd_idx)++; /* Q D D D P */ | |
107 | + qd_idx = 0; | |
108 | + } else if (*dd_idx >= pd_idx) | |
109 | + (*dd_idx) += 2; /* D D P Q D */ | |
110 | + break; | |
111 | + | |
112 | + case ALGORITHM_ROTATING_N_RESTART: | |
113 | + /* Same a left_asymmetric, by first stripe is | |
114 | + * D D D P Q rather than | |
115 | + * Q D D D P | |
116 | + */ | |
117 | + pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks); | |
118 | + qd_idx = pd_idx + 1; | |
119 | + if (pd_idx == raid_disks-1) { | |
120 | + (*dd_idx)++; /* Q D D D P */ | |
121 | + qd_idx = 0; | |
122 | + } else if (*dd_idx >= pd_idx) | |
123 | + (*dd_idx) += 2; /* D D P Q D */ | |
124 | + break; | |
125 | + | |
126 | + case ALGORITHM_ROTATING_N_CONTINUE: | |
127 | + /* Same as left_symmetric but Q is before P */ | |
128 | + pd_idx = raid_disks - 1 - (stripe % raid_disks); | |
129 | + qd_idx = (pd_idx + raid_disks - 1) % raid_disks; | |
130 | + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; | |
131 | + break; | |
132 | + | |
133 | + case ALGORITHM_LEFT_ASYMMETRIC_6: | |
134 | + /* RAID5 left_asymmetric, with Q on last device */ | |
135 | + pd_idx = data_disks - stripe % (raid_disks-1); | |
136 | + if (*dd_idx >= pd_idx) | |
137 | + (*dd_idx)++; | |
138 | + qd_idx = raid_disks - 1; | |
139 | + break; | |
140 | + | |
141 | + case ALGORITHM_RIGHT_ASYMMETRIC_6: | |
142 | + pd_idx = stripe % (raid_disks-1); | |
143 | + if (*dd_idx >= pd_idx) | |
144 | + (*dd_idx)++; | |
145 | + qd_idx = raid_disks - 1; | |
146 | + break; | |
147 | + | |
148 | + case ALGORITHM_LEFT_SYMMETRIC_6: | |
149 | + pd_idx = data_disks - stripe % (raid_disks-1); | |
150 | + *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); | |
151 | + qd_idx = raid_disks - 1; | |
152 | + break; | |
153 | + | |
154 | + case ALGORITHM_RIGHT_SYMMETRIC_6: | |
155 | + pd_idx = stripe % (raid_disks-1); | |
156 | + *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); | |
157 | + qd_idx = raid_disks - 1; | |
158 | + break; | |
159 | + | |
160 | + case ALGORITHM_PARITY_0_6: | |
161 | + pd_idx = 0; | |
162 | + (*dd_idx)++; | |
163 | + qd_idx = raid_disks - 1; | |
164 | + break; | |
165 | + | |
166 | + | |
167 | default: | |
168 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | |
169 | conf->algorithm); | |
170 | + BUG(); | |
171 | } | |
172 | break; | |
173 | } | |
174 | @@ -1413,9 +1500,15 @@ static sector_t compute_blocknr(struct s | |
175 | i += raid_disks; | |
176 | i -= (sh->pd_idx + 1); | |
177 | break; | |
178 | + case ALGORITHM_PARITY_0: | |
179 | + i -= 1; | |
180 | + break; | |
181 | + case ALGORITHM_PARITY_N: | |
182 | + break; | |
183 | default: | |
184 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", | |
185 | conf->algorithm); | |
186 | + BUG(); | |
187 | } | |
188 | break; | |
189 | case 6: | |
190 | @@ -1424,8 +1517,10 @@ static sector_t compute_blocknr(struct s | |
191 | switch (conf->algorithm) { | |
192 | case ALGORITHM_LEFT_ASYMMETRIC: | |
193 | case ALGORITHM_RIGHT_ASYMMETRIC: | |
194 | - if (sh->pd_idx == raid_disks-1) | |
195 | - i--; /* Q D D D P */ | |
196 | + case ALGORITHM_ROTATING_ZERO_RESTART: | |
197 | + case ALGORITHM_ROTATING_N_RESTART: | |
198 | + if (sh->pd_idx == raid_disks-1) | |
199 | + i--; /* Q D D D P */ | |
200 | else if (i > sh->pd_idx) | |
201 | i -= 2; /* D D P Q D */ | |
202 | break; | |
203 | @@ -1440,9 +1535,35 @@ static sector_t compute_blocknr(struct s | |
204 | i -= (sh->pd_idx + 2); | |
205 | } | |
206 | break; | |
207 | + case ALGORITHM_PARITY_0: | |
208 | + i -= 2; | |
209 | + break; | |
210 | + case ALGORITHM_PARITY_N: | |
211 | + break; | |
212 | + case ALGORITHM_ROTATING_N_CONTINUE: | |
213 | + if (sh->pd_idx == 0) | |
214 | + i--; /* P D D D Q */ | |
215 | + else if (i > sh->pd_idx) | |
216 | + i -= 2; /* D D Q P D */ | |
217 | + break; | |
218 | + case ALGORITHM_LEFT_ASYMMETRIC_6: | |
219 | + case ALGORITHM_RIGHT_ASYMMETRIC_6: | |
220 | + if (i > sh->pd_idx) | |
221 | + i--; | |
222 | + break; | |
223 | + case ALGORITHM_LEFT_SYMMETRIC_6: | |
224 | + case ALGORITHM_RIGHT_SYMMETRIC_6: | |
225 | + if (i < sh->pd_idx) | |
226 | + i += data_disks + 1; | |
227 | + i -= (sh->pd_idx + 1); | |
228 | + break; | |
229 | + case ALGORITHM_PARITY_0_6: | |
230 | + i -= 1; | |
231 | + break; | |
232 | default: | |
233 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | |
234 | conf->algorithm); | |
235 | + BUG(); | |
236 | } | |
237 | break; | |
238 | } | |
239 | @@ -3310,7 +3431,7 @@ static int chunk_aligned_read(struct req | |
240 | return 0; | |
241 | } | |
242 | /* | |
243 | - * use bio_clone to make a copy of the bio | |
244 | + * use bio_clone to make a copy of the bio | |
245 | */ | |
246 | align_bi = bio_clone(raid_bio, GFP_NOIO); | |
247 | if (!align_bi) | |
248 | @@ -3438,7 +3559,7 @@ static int make_request(struct request_q | |
249 | if (rw == READ && | |
250 | mddev->reshape_position == MaxSector && | |
251 | chunk_aligned_read(q,bi)) | |
252 | - return 0; | |
253 | + return 0; | |
254 | ||
255 | logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); | |
256 | last_sector = bi->bi_sector + (bi->bi_size>>9); | |
257 | @@ -4034,6 +4155,12 @@ static int run(mddev_t *mddev) | |
258 | mdname(mddev), mddev->level); | |
259 | return -EIO; | |
260 | } | |
261 | + if ((mddev->level == 5 && !algorithm_valid_raid5(mddev->layout)) || | |
262 | + (mddev->level == 6 && !algorithm_valid_raid6(mddev->layout))) { | |
263 | + printk(KERN_ERR "raid5: %s: layout %d not supported\n", | |
264 | + mdname(mddev), mddev->layout); | |
265 | + return -EIO; | |
266 | + } | |
267 | ||
268 | if (mddev->chunk_size < PAGE_SIZE) { | |
269 | printk(KERN_ERR "md/raid5: chunk_size must be at least " | |
270 | @@ -4185,12 +4312,6 @@ static int run(mddev_t *mddev) | |
271 | conf->chunk_size, mdname(mddev)); | |
272 | goto abort; | |
273 | } | |
274 | - if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { | |
275 | - printk(KERN_ERR | |
276 | - "raid5: unsupported parity algorithm %d for %s\n", | |
277 | - conf->algorithm, mdname(mddev)); | |
278 | - goto abort; | |
279 | - } | |
280 | if (mddev->degraded > conf->max_degraded) { | |
281 | printk(KERN_ERR "raid5: not enough operational devices for %s" | |
282 | " (%d/%d failed)\n", | |
283 | --- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/raid5.h | |
284 | +++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/raid5.h | |
285 | @@ -395,9 +395,62 @@ typedef struct raid5_private_data raid5_ | |
286 | /* | |
287 | * Our supported algorithms | |
288 | */ | |
289 | -#define ALGORITHM_LEFT_ASYMMETRIC 0 | |
290 | -#define ALGORITHM_RIGHT_ASYMMETRIC 1 | |
291 | -#define ALGORITHM_LEFT_SYMMETRIC 2 | |
292 | -#define ALGORITHM_RIGHT_SYMMETRIC 3 | |
293 | +#define ALGORITHM_LEFT_ASYMMETRIC 0 /* Rotating Parity N with Data Restart */ | |
294 | +#define ALGORITHM_RIGHT_ASYMMETRIC 1 /* Rotating Parity 0 with Data Restart */ | |
295 | +#define ALGORITHM_LEFT_SYMMETRIC 2 /* Rotating Parity N with Data Continuation */ | |
296 | +#define ALGORITHM_RIGHT_SYMMETRIC 3 /* Rotating Parity 0 with Data Continuation */ | |
297 | ||
298 | +/* Define non-rotating (raid4) algorithms. These allow | |
299 | + * conversion of raid4 to raid5. | |
300 | + */ | |
301 | +#define ALGORITHM_PARITY_0 4 /* P or P,Q are initial devices */ | |
302 | +#define ALGORITHM_PARITY_N 5 /* P or P,Q are final devices. */ | |
303 | + | |
304 | +/* DDF RAID6 layouts differ from md/raid6 layouts in two ways. | |
305 | + * Firstly, the exact positioning of the parity block is slightly | |
306 | + * different between the 'LEFT_*' modes of md and the "_N_*" modes | |
307 | + * of DDF. | |
308 | + * Secondly, or order of datablocks over which the Q syndrome is computed | |
309 | + * is different. | |
310 | + * Consequently we have different layouts for DDF/raid6 than md/raid6. | |
311 | + * These layouts are from the DDFv1.2 spec. | |
312 | + * Interestingly DDFv1.2-Errata-A does not specify N_CONTINUE but | |
313 | + * leaves RLQ=3 as 'Vendor Specific' | |
314 | + */ | |
315 | + | |
316 | +#define ALGORITHM_ROTATING_ZERO_RESTART 8 /* DDF PRL=6 RLQ=1 */ | |
317 | +#define ALGORITHM_ROTATING_N_RESTART 9 /* DDF PRL=6 RLQ=2 */ | |
318 | +#define ALGORITHM_ROTATING_N_CONTINUE 10 /*DDF PRL=6 RLQ=3 */ | |
319 | + | |
320 | + | |
321 | +/* For every RAID5 algorithm we define a RAID6 algorithm | |
322 | + * with exactly the same layout for data and parity, and | |
323 | + * with the Q block always on the last device (N-1). | |
324 | + * This allows trivial conversion from RAID5 to RAID6 | |
325 | + */ | |
326 | +#define ALGORITHM_LEFT_ASYMMETRIC_6 16 | |
327 | +#define ALGORITHM_RIGHT_ASYMMETRIC_6 17 | |
328 | +#define ALGORITHM_LEFT_SYMMETRIC_6 18 | |
329 | +#define ALGORITHM_RIGHT_SYMMETRIC_6 19 | |
330 | +#define ALGORITHM_PARITY_0_6 20 | |
331 | +#define ALGORITHM_PARITY_N_6 ALGORITHM_PARITY_N | |
332 | + | |
333 | +static inline int algorithm_valid_raid5(int layout) | |
334 | +{ | |
335 | + return (layout >= 0) && | |
336 | + (layout <= 5); | |
337 | +} | |
338 | +static inline int algorithm_valid_raid6(int layout) | |
339 | +{ | |
340 | + return (layout >= 0 && layout <= 5) | |
341 | + || | |
342 | + (layout == 8 || layout == 10) | |
343 | + || | |
344 | + (layout >= 16 && layout <= 20); | |
345 | +} | |
346 | + | |
347 | +static inline int algorithm_is_DDF(int layout) | |
348 | +{ | |
349 | + return layout >= 8 && layout <= 10; | |
350 | +} | |
351 | #endif |