Commit da17bf43 authored by Dan Williams's avatar Dan Williams

async_tx: fix asynchronous raid6 recovery for ddf layouts

The raid6 recovery code currently requires special handling of the
4-disk and 5-disk recovery scenarios for the native layout.  Quoting
from commit 0a82a623:

     In these situations the default N-disk algorithm will present
     0-source or 1-source operations to dma devices.  To cover for
     dma devices where the minimum source count is 2 we implement
     4-disk and 5-disk handling in the recovery code.

The ddf layout presents disks=6 and disks=7 to the recovery code in
these situations.  Instead of looking at the number of disks count the
number of non-zero sources in the list and call the special case code
when the number of non-failed sources is 0 or 1.

[neilb@suse.de: replace 'ddf' flag with counting good sources]
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 030b0772
...@@ -131,8 +131,8 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len, ...@@ -131,8 +131,8 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
} }
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
__2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks, __2data_recov_4(int disks, size_t bytes, int faila, int failb,
struct async_submit_ctl *submit) struct page **blocks, struct async_submit_ctl *submit)
{ {
struct dma_async_tx_descriptor *tx = NULL; struct dma_async_tx_descriptor *tx = NULL;
struct page *p, *q, *a, *b; struct page *p, *q, *a, *b;
...@@ -143,8 +143,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks, ...@@ -143,8 +143,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks,
void *cb_param = submit->cb_param; void *cb_param = submit->cb_param;
void *scribble = submit->scribble; void *scribble = submit->scribble;
p = blocks[4-2]; p = blocks[disks-2];
q = blocks[4-1]; q = blocks[disks-1];
a = blocks[faila]; a = blocks[faila];
b = blocks[failb]; b = blocks[failb];
...@@ -170,8 +170,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks, ...@@ -170,8 +170,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks,
} }
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
__2data_recov_5(size_t bytes, int faila, int failb, struct page **blocks, __2data_recov_5(int disks, size_t bytes, int faila, int failb,
struct async_submit_ctl *submit) struct page **blocks, struct async_submit_ctl *submit)
{ {
struct dma_async_tx_descriptor *tx = NULL; struct dma_async_tx_descriptor *tx = NULL;
struct page *p, *q, *g, *dp, *dq; 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,21 +181,22 @@ __2data_recov_5(size_t bytes, int faila, int failb, struct page **blocks,
dma_async_tx_callback cb_fn = submit->cb_fn; dma_async_tx_callback cb_fn = submit->cb_fn;
void *cb_param = submit->cb_param; void *cb_param = submit->cb_param;
void *scribble = submit->scribble; void *scribble = submit->scribble;
int uninitialized_var(good); int good_srcs, good, i;
int i;
for (i = 0; i < 3; i++) { good_srcs = 0;
good = -1;
for (i = 0; i < disks-2; i++) {
if (blocks[i] == NULL)
continue;
if (i == faila || i == failb) if (i == faila || i == failb)
continue; continue;
else { good = i;
good = i; good_srcs++;
break;
}
} }
BUG_ON(i >= 3); BUG_ON(good_srcs > 1);
p = blocks[5-2]; p = blocks[disks-2];
q = blocks[5-1]; q = blocks[disks-1];
g = blocks[good]; g = blocks[good];
/* Compute syndrome with zero for the missing data pages /* Compute syndrome with zero for the missing data pages
...@@ -323,6 +324,8 @@ struct dma_async_tx_descriptor * ...@@ -323,6 +324,8 @@ struct dma_async_tx_descriptor *
async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
struct page **blocks, struct async_submit_ctl *submit) struct page **blocks, struct async_submit_ctl *submit)
{ {
int non_zero_srcs, i;
BUG_ON(faila == failb); BUG_ON(faila == failb);
if (failb < faila) if (failb < faila)
swap(faila, failb); swap(faila, failb);
...@@ -334,12 +337,11 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, ...@@ -334,12 +337,11 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
*/ */
if (!submit->scribble) { if (!submit->scribble) {
void **ptrs = (void **) blocks; void **ptrs = (void **) blocks;
int i;
async_tx_quiesce(&submit->depend_tx); async_tx_quiesce(&submit->depend_tx);
for (i = 0; i < disks; i++) for (i = 0; i < disks; i++)
if (blocks[i] == NULL) if (blocks[i] == NULL)
ptrs[i] = (void*)raid6_empty_zero_page; ptrs[i] = (void *) raid6_empty_zero_page;
else else
ptrs[i] = page_address(blocks[i]); ptrs[i] = page_address(blocks[i]);
...@@ -350,19 +352,30 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, ...@@ -350,19 +352,30 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
return NULL; return NULL;
} }
switch (disks) { non_zero_srcs = 0;
case 4: for (i = 0; i < disks-2 && non_zero_srcs < 4; i++)
if (blocks[i])
non_zero_srcs++;
switch (non_zero_srcs) {
case 0:
case 1:
/* There must be at least 2 sources - the failed devices. */
BUG();
case 2:
/* dma devices do not uniformly understand a zero source pq /* dma devices do not uniformly understand a zero source pq
* operation (in contrast to the synchronous case), so * operation (in contrast to the synchronous case), so
* explicitly handle the 4 disk special case * explicitly handle the special case of a 4 disk array with
* both data disks missing.
*/ */
return __2data_recov_4(bytes, faila, failb, blocks, submit); return __2data_recov_4(disks, bytes, faila, failb, blocks, submit);
case 5: case 3:
/* dma devices do not uniformly understand a single /* dma devices do not uniformly understand a single
* source pq operation (in contrast to the synchronous * source pq operation (in contrast to the synchronous
* case), so explicitly handle the 5 disk special case * case), so explicitly handle the special case of a 5 disk
* array with 2 of 3 data disks missing.
*/ */
return __2data_recov_5(bytes, faila, failb, blocks, submit); return __2data_recov_5(disks, bytes, faila, failb, blocks, submit);
default: default:
return __2data_recov_n(disks, bytes, faila, failb, blocks, submit); return __2data_recov_n(disks, bytes, faila, failb, blocks, submit);
} }
...@@ -388,6 +401,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, ...@@ -388,6 +401,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
dma_async_tx_callback cb_fn = submit->cb_fn; dma_async_tx_callback cb_fn = submit->cb_fn;
void *cb_param = submit->cb_param; void *cb_param = submit->cb_param;
void *scribble = submit->scribble; void *scribble = submit->scribble;
int good_srcs, good, i;
struct page *srcs[2]; struct page *srcs[2];
pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes); pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes);
...@@ -397,7 +411,6 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, ...@@ -397,7 +411,6 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
*/ */
if (!scribble) { if (!scribble) {
void **ptrs = (void **) blocks; void **ptrs = (void **) blocks;
int i;
async_tx_quiesce(&submit->depend_tx); async_tx_quiesce(&submit->depend_tx);
for (i = 0; i < disks; i++) for (i = 0; i < disks; i++)
...@@ -413,6 +426,20 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, ...@@ -413,6 +426,20 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
return NULL; return NULL;
} }
good_srcs = 0;
good = -1;
for (i = 0; i < disks-2; i++) {
if (i == faila)
continue;
if (blocks[i]) {
good = i;
good_srcs++;
if (good_srcs > 1)
break;
}
}
BUG_ON(good_srcs == 0);
p = blocks[disks-2]; p = blocks[disks-2];
q = blocks[disks-1]; q = blocks[disks-1];
...@@ -423,11 +450,10 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila, ...@@ -423,11 +450,10 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
blocks[faila] = NULL; blocks[faila] = NULL;
blocks[disks-1] = dq; blocks[disks-1] = dq;
/* in the 4 disk case we only need to perform a single source /* in the 4-disk case we only need to perform a single source
* multiplication * multiplication with the one good data block.
*/ */
if (disks == 4) { if (good_srcs == 1) {
int good = faila == 0 ? 1 : 0;
struct page *g = blocks[good]; struct page *g = blocks[good];
init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment