diff options
Diffstat (limited to 'crypto/async_tx/async_raid6_recov.c')
-rw-r--r-- | crypto/async_tx/async_raid6_recov.c | 100 |
1 files changed, 66 insertions, 34 deletions
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c index 6d73dde4786d..943f2abac9b4 100644 --- a/crypto/async_tx/async_raid6_recov.c +++ b/crypto/async_tx/async_raid6_recov.c | |||
@@ -131,8 +131,8 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len, | |||
131 | } | 131 | } |
132 | 132 | ||
133 | static struct dma_async_tx_descriptor * | 133 | static struct dma_async_tx_descriptor * |
134 | __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks, | 134 | __2data_recov_4(int disks, size_t bytes, int faila, int failb, |
135 | struct async_submit_ctl *submit) | 135 | struct page **blocks, struct async_submit_ctl *submit) |
136 | { | 136 | { |
137 | struct dma_async_tx_descriptor *tx = NULL; | 137 | struct dma_async_tx_descriptor *tx = NULL; |
138 | struct page *p, *q, *a, *b; | 138 | struct page *p, *q, *a, *b; |
@@ -143,8 +143,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks, | |||
143 | void *cb_param = submit->cb_param; | 143 | void *cb_param = submit->cb_param; |
144 | void *scribble = submit->scribble; | 144 | void *scribble = submit->scribble; |
145 | 145 | ||
146 | p = blocks[4-2]; | 146 | p = blocks[disks-2]; |
147 | q = blocks[4-1]; | 147 | q = blocks[disks-1]; |
148 | 148 | ||
149 | a = blocks[faila]; | 149 | a = blocks[faila]; |
150 | b = blocks[failb]; | 150 | b = blocks[failb]; |
@@ -170,8 +170,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks, | |||
170 | } | 170 | } |
171 | 171 | ||
172 | static struct dma_async_tx_descriptor * | 172 | static struct dma_async_tx_descriptor * |
173 | __2data_recov_5(size_t bytes, int faila, int failb, struct page **blocks, | 173 | __2data_recov_5(int disks, size_t bytes, int faila, int failb, |
174 | struct async_submit_ctl *submit) | 174 | struct page **blocks, struct async_submit_ctl *submit) |
175 | { | 175 | { |
176 | struct dma_async_tx_descriptor *tx = NULL; | 176 | struct dma_async_tx_descriptor *tx = NULL; |
177 | struct page *p, *q, *g, *dp, *dq; | 177 | struct page *p, *q, *g, *dp, *dq; |
@@ -181,21 +181,22 @@ __2data_recov_5(size_t bytes, int faila, int failb, struct page **blocks, | |||
181 | dma_async_tx_callback cb_fn = submit->cb_fn; | 181 | dma_async_tx_callback cb_fn = submit->cb_fn; |
182 | void *cb_param = submit->cb_param; | 182 | void *cb_param = submit->cb_param; |
183 | void *scribble = submit->scribble; | 183 | void *scribble = submit->scribble; |
184 | int uninitialized_var(good); | 184 | int good_srcs, good, i; |
185 | int i; | ||
186 | 185 | ||
187 | for (i = 0; i < 3; i++) { | 186 | good_srcs = 0; |
187 | good = -1; | ||
188 | for (i = 0; i < disks-2; i++) { | ||
189 | if (blocks[i] == NULL) | ||
190 | continue; | ||
188 | if (i == faila || i == failb) | 191 | if (i == faila || i == failb) |
189 | continue; | 192 | continue; |
190 | else { | 193 | good = i; |
191 | good = i; | 194 | good_srcs++; |
192 | break; | ||
193 | } | ||
194 | } | 195 | } |
195 | BUG_ON(i >= 3); | 196 | BUG_ON(good_srcs > 1); |
196 | 197 | ||
197 | p = blocks[5-2]; | 198 | p = blocks[disks-2]; |
198 | q = blocks[5-1]; | 199 | q = blocks[disks-1]; |
199 | g = blocks[good]; | 200 | g = blocks[good]; |
200 | 201 | ||
201 | /* Compute syndrome with zero for the missing data pages | 202 | /* Compute syndrome with zero for the missing data pages |
@@ -263,10 +264,10 @@ __2data_recov_n(int disks, size_t bytes, int faila, int failb, | |||
263 | * delta p and delta q | 264 | * delta p and delta q |
264 | */ | 265 | */ |
265 | dp = blocks[faila]; | 266 | dp = blocks[faila]; |
266 | blocks[faila] = (void *)raid6_empty_zero_page; | 267 | blocks[faila] = NULL; |
267 | blocks[disks-2] = dp; | 268 | blocks[disks-2] = dp; |
268 | dq = blocks[failb]; | 269 | dq = blocks[failb]; |
269 | blocks[failb] = (void *)raid6_empty_zero_page; | 270 | blocks[failb] = NULL; |
270 | blocks[disks-1] = dq; | 271 | blocks[disks-1] = dq; |
271 | 272 | ||
272 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); | 273 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
@@ -323,6 +324,8 @@ struct dma_async_tx_descriptor * | |||
323 | async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, | 324 | async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, |
324 | struct page **blocks, struct async_submit_ctl *submit) | 325 | struct page **blocks, struct async_submit_ctl *submit) |
325 | { | 326 | { |
327 | int non_zero_srcs, i; | ||
328 | |||
326 | BUG_ON(faila == failb); | 329 | BUG_ON(faila == failb); |
327 | if (failb < faila) | 330 | if (failb < faila) |
328 | swap(faila, failb); | 331 | swap(faila, failb); |
@@ -334,11 +337,13 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, | |||
334 | */ | 337 | */ |
335 | if (!submit->scribble) { | 338 | if (!submit->scribble) { |
336 | void **ptrs = (void **) blocks; | 339 | void **ptrs = (void **) blocks; |
337 | int i; | ||
338 | 340 | ||
339 | async_tx_quiesce(&submit->depend_tx); | 341 | async_tx_quiesce(&submit->depend_tx); |
340 | for (i = 0; i < disks; i++) | 342 | for (i = 0; i < disks; i++) |
341 | ptrs[i] = page_address(blocks[i]); | 343 | if (blocks[i] == NULL) |
344 | ptrs[i] = (void *) raid6_empty_zero_page; | ||
345 | else | ||
346 | ptrs[i] = page_address(blocks[i]); | ||
342 | 347 | ||
343 | raid6_2data_recov(disks, bytes, faila, failb, ptrs); | 348 | raid6_2data_recov(disks, bytes, faila, failb, ptrs); |
344 | 349 | ||
@@ -347,19 +352,30 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, | |||
347 | return NULL; | 352 | return NULL; |
348 | } | 353 | } |
349 | 354 | ||
350 | switch (disks) { | 355 | non_zero_srcs = 0; |
351 | case 4: | 356 | for (i = 0; i < disks-2 && non_zero_srcs < 4; i++) |
357 | if (blocks[i]) | ||
358 | non_zero_srcs++; | ||
359 | switch (non_zero_srcs) { | ||
360 | case 0: | ||
361 | case 1: | ||
362 | /* There must be at least 2 sources - the failed devices. */ | ||
363 | BUG(); | ||
364 | |||
365 | case 2: | ||
352 | /* dma devices do not uniformly understand a zero source pq | 366 | /* dma devices do not uniformly understand a zero source pq |
353 | * operation (in contrast to the synchronous case), so | 367 | * operation (in contrast to the synchronous case), so |
354 | * explicitly handle the 4 disk special case | 368 | * explicitly handle the special case of a 4 disk array with |
369 | * both data disks missing. | ||
355 | */ | 370 | */ |
356 | return __2data_recov_4(bytes, faila, failb, blocks, submit); | 371 | return __2data_recov_4(disks, bytes, faila, failb, blocks, submit); |
357 | case 5: | 372 | case 3: |
358 | /* dma devices do not uniformly understand a single | 373 | /* dma devices do not uniformly understand a single |
359 | * source pq operation (in contrast to the synchronous | 374 | * source pq operation (in contrast to the synchronous |
360 | * case), so explicitly handle the 5 disk special case | 375 | * case), so explicitly handle the special case of a 5 disk |
376 | * array with 2 of 3 data disks missing. | ||
361 | */ | 377 | */ |
362 | return __2data_recov_5(bytes, faila, failb, blocks, submit); | 378 | return __2data_recov_5(disks, bytes, faila, failb, blocks, submit); |
363 | default: | 379 | default: |
364 | return __2data_recov_n(disks, bytes, faila, failb, blocks, submit); | 380 | return __2data_recov_n(disks, bytes, faila, failb, blocks, submit); |
365 | } | 381 | } |
@@ -385,6 +401,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, | |||
385 | dma_async_tx_callback cb_fn = submit->cb_fn; | 401 | dma_async_tx_callback cb_fn = submit->cb_fn; |
386 | void *cb_param = submit->cb_param; | 402 | void *cb_param = submit->cb_param; |
387 | void *scribble = submit->scribble; | 403 | void *scribble = submit->scribble; |
404 | int good_srcs, good, i; | ||
388 | struct page *srcs[2]; | 405 | struct page *srcs[2]; |
389 | 406 | ||
390 | pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes); | 407 | pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes); |
@@ -394,11 +411,13 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, | |||
394 | */ | 411 | */ |
395 | if (!scribble) { | 412 | if (!scribble) { |
396 | void **ptrs = (void **) blocks; | 413 | void **ptrs = (void **) blocks; |
397 | int i; | ||
398 | 414 | ||
399 | async_tx_quiesce(&submit->depend_tx); | 415 | async_tx_quiesce(&submit->depend_tx); |
400 | for (i = 0; i < disks; i++) | 416 | for (i = 0; i < disks; i++) |
401 | ptrs[i] = page_address(blocks[i]); | 417 | if (blocks[i] == NULL) |
418 | ptrs[i] = (void*)raid6_empty_zero_page; | ||
419 | else | ||
420 | ptrs[i] = page_address(blocks[i]); | ||
402 | 421 | ||
403 | raid6_datap_recov(disks, bytes, faila, ptrs); | 422 | raid6_datap_recov(disks, bytes, faila, ptrs); |
404 | 423 | ||
@@ -407,6 +426,20 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, | |||
407 | return NULL; | 426 | return NULL; |
408 | } | 427 | } |
409 | 428 | ||
429 | good_srcs = 0; | ||
430 | good = -1; | ||
431 | for (i = 0; i < disks-2; i++) { | ||
432 | if (i == faila) | ||
433 | continue; | ||
434 | if (blocks[i]) { | ||
435 | good = i; | ||
436 | good_srcs++; | ||
437 | if (good_srcs > 1) | ||
438 | break; | ||
439 | } | ||
440 | } | ||
441 | BUG_ON(good_srcs == 0); | ||
442 | |||
410 | p = blocks[disks-2]; | 443 | p = blocks[disks-2]; |
411 | q = blocks[disks-1]; | 444 | q = blocks[disks-1]; |
412 | 445 | ||
@@ -414,14 +447,13 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, | |||
414 | * Use the dead data page as temporary storage for delta q | 447 | * Use the dead data page as temporary storage for delta q |
415 | */ | 448 | */ |
416 | dq = blocks[faila]; | 449 | dq = blocks[faila]; |
417 | blocks[faila] = (void *)raid6_empty_zero_page; | 450 | blocks[faila] = NULL; |
418 | blocks[disks-1] = dq; | 451 | blocks[disks-1] = dq; |
419 | 452 | ||
420 | /* in the 4 disk case we only need to perform a single source | 453 | /* in the 4-disk case we only need to perform a single source |
421 | * multiplication | 454 | * multiplication with the one good data block. |
422 | */ | 455 | */ |
423 | if (disks == 4) { | 456 | if (good_srcs == 1) { |
424 | int good = faila == 0 ? 1 : 0; | ||
425 | struct page *g = blocks[good]; | 457 | struct page *g = blocks[good]; |
426 | 458 | ||
427 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, | 459 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, |