unmap->addr[2] = dma_map_page(dev, dest, d_off,
len, DMA_BIDIRECTIONAL);
unmap->bidi_cnt = 1; /* engine only looks at Q, but expects it to follow P */
pq[1] = unmap->addr[2];
/* this looks funny, but the engine looks for Q at * dma_dest[1] and ignores dma_dest[0] as a dest * due to DMA_PREP_PQ_DISABLE_P
*/
tx = dma->device_prep_dma_pq(chan, dma_dest, unmap->addr,
1, &coef, len, dma_flags);
/* could not get a descriptor, unmap and fall through to * the synchronous path
*/
dmaengine_unmap_put(unmap);
}
/* no channel available, or failed to allocate a descriptor, so * perform the operation synchronously
*/
async_tx_quiesce(&submit->depend_tx);
qmul = raid6_gfmul[coef];
d = page_address(dest) + d_off;
s = page_address(src) + s_off;
good_srcs = 0;
good = -1; for (i = 0; i < disks-2; i++) { if (blocks[i] == NULL) continue; if (i == faila || i == failb) continue;
good = i;
good_srcs++;
}
BUG_ON(good_srcs > 1);
p = blocks[disks-2];
p_off = offs[disks-2];
q = blocks[disks-1];
q_off = offs[disks-1];
g = blocks[good];
g_off = offs[good];
/* Compute syndrome with zero for the missing data pages * Use the dead data pages as temporary storage for delta p and * delta q
*/
dp = blocks[faila];
dp_off = offs[faila];
dq = blocks[failb];
dq_off = offs[failb];
/* Compute syndrome with zero for the missing data pages * Use the dead data pages as temporary storage for * delta p and delta q
*/
dp = blocks[faila];
dp_off = offs[faila];
blocks[faila] = NULL;
blocks[disks-2] = dp;
offs[disks-2] = dp_off;
dq = blocks[failb];
dq_off = offs[failb];
blocks[failb] = NULL;
blocks[disks-1] = dq;
offs[disks-1] = dq_off;
/** * async_raid6_2data_recov - asynchronously calculate two missing data blocks * @disks: number of disks in the RAID-6 array * @bytes: block size * @faila: first failed drive index * @failb: second failed drive index * @blocks: array of source pointers where the last two entries are p and q * @offs: array of offset for pages in blocks * @submit: submission/completion modifiers
*/ struct dma_async_tx_descriptor *
async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, struct page **blocks, unsignedint *offs, struct async_submit_ctl *submit)
{ void *scribble = submit->scribble; int non_zero_srcs, i;
BUG_ON(faila == failb); if (failb < faila)
swap(faila, failb);
/* if a dma resource is not available or a scribble buffer is not * available punt to the synchronous path. In the 'dma not * available' case be sure to use the scribble buffer to * preserve the content of 'blocks' as the caller intended.
*/ if (!async_dma_find_channel(DMA_PQ) || !scribble) { void **ptrs = scribble ? scribble : (void **) blocks;
async_tx_quiesce(&submit->depend_tx); for (i = 0; i < disks; i++) if (blocks[i] == NULL)
ptrs[i] = raid6_get_zero_page(); else
ptrs[i] = page_address(blocks[i]) + offs[i];
non_zero_srcs = 0; 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 * operation (in contrast to the synchronous case), so * explicitly handle the special case of a 4 disk array with * both data disks missing.
*/ return __2data_recov_4(disks, bytes, faila, failb,
blocks, offs, submit); case 3: /* dma devices do not uniformly understand a single * source pq operation (in contrast to the synchronous * case), so explicitly handle the special case of a 5 disk * array with 2 of 3 data disks missing.
*/ return __2data_recov_5(disks, bytes, faila, failb,
blocks, offs, submit); default: return __2data_recov_n(disks, bytes, faila, failb,
blocks, offs, submit);
}
}
EXPORT_SYMBOL_GPL(async_raid6_2data_recov);
/** * async_raid6_datap_recov - asynchronously calculate a data and the 'p' block * @disks: number of disks in the RAID-6 array * @bytes: block size * @faila: failed drive index * @blocks: array of source pointers where the last two entries are p and q * @offs: array of offset for pages in blocks * @submit: submission/completion modifiers
*/ struct dma_async_tx_descriptor *
async_raid6_datap_recov(int disks, size_t bytes, int faila, struct page **blocks, unsignedint *offs, struct async_submit_ctl *submit)
{ struct dma_async_tx_descriptor *tx = NULL; struct page *p, *q, *dq; unsignedint p_off, q_off, dq_off;
u8 coef; enum async_tx_flags flags = submit->flags;
dma_async_tx_callback cb_fn = submit->cb_fn; void *cb_param = submit->cb_param; void *scribble = submit->scribble; int good_srcs, good, i; struct page *srcs[2]; unsignedint src_offs[2];
/* if a dma resource is not available or a scribble buffer is not * available punt to the synchronous path. In the 'dma not * available' case be sure to use the scribble buffer to * preserve the content of 'blocks' as the caller intended.
*/ if (!async_dma_find_channel(DMA_PQ) || !scribble) { void **ptrs = scribble ? scribble : (void **) blocks;
async_tx_quiesce(&submit->depend_tx); for (i = 0; i < disks; i++) if (blocks[i] == NULL)
ptrs[i] = raid6_get_zero_page(); else
ptrs[i] = page_address(blocks[i]) + offs[i];
raid6_datap_recov(disks, bytes, faila, ptrs);
async_tx_sync_epilog(submit);
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);
/* Compute syndrome with zero for the missing data page * Use the dead data page as temporary storage for delta q
*/
dq = blocks[faila];
dq_off = offs[faila];
blocks[faila] = NULL;
blocks[disks-1] = dq;
offs[disks-1] = dq_off;
/* in the 4-disk case we only need to perform a single source * multiplication with the one good data block.
*/ if (good_srcs == 1) { struct page *g = blocks[good]; unsignedint g_off = offs[good];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.