Commit 163090c1 authored by Jens Axboe's avatar Jens Axboe

Merge branch 'md-next' of...

Merge branch 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md into for-5.10/drivers

Pull MD updates from Song.

* 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md:
  md/raid10: improve discard request for far layout
  md/raid10: improve raid10 discard request
  md/raid10: pull codes that wait for blocked dev into one function
  md/raid10: extend r10bio devs to raid disks
  md: add md_submit_discard_bio() for submitting discard bio
  md: Simplify code with existing definition RESYNC_SECTORS in raid10.c
  md/raid5: reallocate page array after setting new stripe_size
  md/raid5: resize stripe_head when reshape array
  md/raid5: let multiple devices of stripe_head share page
  md/raid6: let async recovery function support different page offset
  md/raid6: let syndrome computor support different page offset
  md/raid5: convert to new xor compution interface
  md/raid5: add new xor function to support different page offset
  md/raid5: make async_copy_data() to support different page offset
  md/raid5: add a new member of offset into r5dev
  md: only calculate blocksize once and use i_blocksize()
parents 0905053b d3ee2d84
...@@ -104,7 +104,7 @@ do_async_gen_syndrome(struct dma_chan *chan, ...@@ -104,7 +104,7 @@ do_async_gen_syndrome(struct dma_chan *chan,
* do_sync_gen_syndrome - synchronously calculate a raid6 syndrome * do_sync_gen_syndrome - synchronously calculate a raid6 syndrome
*/ */
static void static void
do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
size_t len, struct async_submit_ctl *submit) size_t len, struct async_submit_ctl *submit)
{ {
void **srcs; void **srcs;
...@@ -121,7 +121,8 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -121,7 +121,8 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
BUG_ON(i > disks - 3); /* P or Q can't be zero */ BUG_ON(i > disks - 3); /* P or Q can't be zero */
srcs[i] = (void*)raid6_empty_zero_page; srcs[i] = (void*)raid6_empty_zero_page;
} else { } else {
srcs[i] = page_address(blocks[i]) + offset; srcs[i] = page_address(blocks[i]) + offsets[i];
if (i < disks - 2) { if (i < disks - 2) {
stop = i; stop = i;
if (start == -1) if (start == -1)
...@@ -138,10 +139,23 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -138,10 +139,23 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
async_tx_sync_epilog(submit); async_tx_sync_epilog(submit);
} }
static inline bool
is_dma_pq_aligned_offs(struct dma_device *dev, unsigned int *offs,
int src_cnt, size_t len)
{
int i;
for (i = 0; i < src_cnt; i++) {
if (!is_dma_pq_aligned(dev, offs[i], 0, len))
return false;
}
return true;
}
/** /**
* async_gen_syndrome - asynchronously calculate a raid6 syndrome * async_gen_syndrome - asynchronously calculate a raid6 syndrome
* @blocks: source blocks from idx 0..disks-3, P @ disks-2 and Q @ disks-1 * @blocks: source blocks from idx 0..disks-3, P @ disks-2 and Q @ disks-1
* @offset: common offset into each block (src and dest) to start transaction * @offsets: offset array into each block (src and dest) to start transaction
* @disks: number of blocks (including missing P or Q, see below) * @disks: number of blocks (including missing P or Q, see below)
* @len: length of operation in bytes * @len: length of operation in bytes
* @submit: submission/completion modifiers * @submit: submission/completion modifiers
...@@ -160,7 +174,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -160,7 +174,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
* path. * path.
*/ */
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, async_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
size_t len, struct async_submit_ctl *submit) size_t len, struct async_submit_ctl *submit)
{ {
int src_cnt = disks - 2; int src_cnt = disks - 2;
...@@ -179,7 +193,7 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -179,7 +193,7 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) && if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) &&
(src_cnt <= dma_maxpq(device, 0) || (src_cnt <= dma_maxpq(device, 0) ||
dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && dma_maxpq(device, DMA_PREP_CONTINUE) > 0) &&
is_dma_pq_aligned(device, offset, 0, len)) { is_dma_pq_aligned_offs(device, offsets, disks, len)) {
struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx;
enum dma_ctrl_flags dma_flags = 0; enum dma_ctrl_flags dma_flags = 0;
unsigned char coefs[MAX_DISKS]; unsigned char coefs[MAX_DISKS];
...@@ -196,8 +210,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -196,8 +210,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
for (i = 0, j = 0; i < src_cnt; i++) { for (i = 0, j = 0; i < src_cnt; i++) {
if (blocks[i] == NULL) if (blocks[i] == NULL)
continue; continue;
unmap->addr[j] = dma_map_page(device->dev, blocks[i], offset, unmap->addr[j] = dma_map_page(device->dev, blocks[i],
len, DMA_TO_DEVICE); offsets[i], len, DMA_TO_DEVICE);
coefs[j] = raid6_gfexp[i]; coefs[j] = raid6_gfexp[i];
unmap->to_cnt++; unmap->to_cnt++;
j++; j++;
...@@ -210,7 +224,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -210,7 +224,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
unmap->bidi_cnt++; unmap->bidi_cnt++;
if (P(blocks, disks)) if (P(blocks, disks))
unmap->addr[j++] = dma_map_page(device->dev, P(blocks, disks), unmap->addr[j++] = dma_map_page(device->dev, P(blocks, disks),
offset, len, DMA_BIDIRECTIONAL); P(offsets, disks),
len, DMA_BIDIRECTIONAL);
else { else {
unmap->addr[j++] = 0; unmap->addr[j++] = 0;
dma_flags |= DMA_PREP_PQ_DISABLE_P; dma_flags |= DMA_PREP_PQ_DISABLE_P;
...@@ -219,7 +234,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -219,7 +234,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
unmap->bidi_cnt++; unmap->bidi_cnt++;
if (Q(blocks, disks)) if (Q(blocks, disks))
unmap->addr[j++] = dma_map_page(device->dev, Q(blocks, disks), unmap->addr[j++] = dma_map_page(device->dev, Q(blocks, disks),
offset, len, DMA_BIDIRECTIONAL); Q(offsets, disks),
len, DMA_BIDIRECTIONAL);
else { else {
unmap->addr[j++] = 0; unmap->addr[j++] = 0;
dma_flags |= DMA_PREP_PQ_DISABLE_Q; dma_flags |= DMA_PREP_PQ_DISABLE_Q;
...@@ -240,13 +256,13 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, ...@@ -240,13 +256,13 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
if (!P(blocks, disks)) { if (!P(blocks, disks)) {
P(blocks, disks) = pq_scribble_page; P(blocks, disks) = pq_scribble_page;
BUG_ON(len + offset > PAGE_SIZE); P(offsets, disks) = 0;
} }
if (!Q(blocks, disks)) { if (!Q(blocks, disks)) {
Q(blocks, disks) = pq_scribble_page; Q(blocks, disks) = pq_scribble_page;
BUG_ON(len + offset > PAGE_SIZE); Q(offsets, disks) = 0;
} }
do_sync_gen_syndrome(blocks, offset, disks, len, submit); do_sync_gen_syndrome(blocks, offsets, disks, len, submit);
return NULL; return NULL;
} }
...@@ -270,6 +286,7 @@ pq_val_chan(struct async_submit_ctl *submit, struct page **blocks, int disks, si ...@@ -270,6 +286,7 @@ pq_val_chan(struct async_submit_ctl *submit, struct page **blocks, int disks, si
* @len: length of operation in bytes * @len: length of operation in bytes
* @pqres: on val failure SUM_CHECK_P_RESULT and/or SUM_CHECK_Q_RESULT are set * @pqres: on val failure SUM_CHECK_P_RESULT and/or SUM_CHECK_Q_RESULT are set
* @spare: temporary result buffer for the synchronous case * @spare: temporary result buffer for the synchronous case
* @s_off: spare buffer page offset
* @submit: submission / completion modifiers * @submit: submission / completion modifiers
* *
* The same notes from async_gen_syndrome apply to the 'blocks', * The same notes from async_gen_syndrome apply to the 'blocks',
...@@ -278,9 +295,9 @@ pq_val_chan(struct async_submit_ctl *submit, struct page **blocks, int disks, si ...@@ -278,9 +295,9 @@ pq_val_chan(struct async_submit_ctl *submit, struct page **blocks, int disks, si
* specified. * specified.
*/ */
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_syndrome_val(struct page **blocks, unsigned int offset, int disks, async_syndrome_val(struct page **blocks, unsigned int *offsets, int disks,
size_t len, enum sum_check_flags *pqres, struct page *spare, size_t len, enum sum_check_flags *pqres, struct page *spare,
struct async_submit_ctl *submit) unsigned int s_off, struct async_submit_ctl *submit)
{ {
struct dma_chan *chan = pq_val_chan(submit, blocks, disks, len); struct dma_chan *chan = pq_val_chan(submit, blocks, disks, len);
struct dma_device *device = chan ? chan->device : NULL; struct dma_device *device = chan ? chan->device : NULL;
...@@ -295,7 +312,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, ...@@ -295,7 +312,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT); unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT);
if (unmap && disks <= dma_maxpq(device, 0) && if (unmap && disks <= dma_maxpq(device, 0) &&
is_dma_pq_aligned(device, offset, 0, len)) { is_dma_pq_aligned_offs(device, offsets, disks, len)) {
struct device *dev = device->dev; struct device *dev = device->dev;
dma_addr_t pq[2]; dma_addr_t pq[2];
int i, j = 0, src_cnt = 0; int i, j = 0, src_cnt = 0;
...@@ -307,7 +324,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, ...@@ -307,7 +324,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
for (i = 0; i < disks-2; i++) for (i = 0; i < disks-2; i++)
if (likely(blocks[i])) { if (likely(blocks[i])) {
unmap->addr[j] = dma_map_page(dev, blocks[i], unmap->addr[j] = dma_map_page(dev, blocks[i],
offset, len, offsets[i], len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
coefs[j] = raid6_gfexp[i]; coefs[j] = raid6_gfexp[i];
unmap->to_cnt++; unmap->to_cnt++;
...@@ -320,7 +337,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, ...@@ -320,7 +337,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
dma_flags |= DMA_PREP_PQ_DISABLE_P; dma_flags |= DMA_PREP_PQ_DISABLE_P;
} else { } else {
pq[0] = dma_map_page(dev, P(blocks, disks), pq[0] = dma_map_page(dev, P(blocks, disks),
offset, len, P(offsets, disks), len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
unmap->addr[j++] = pq[0]; unmap->addr[j++] = pq[0];
unmap->to_cnt++; unmap->to_cnt++;
...@@ -330,7 +347,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, ...@@ -330,7 +347,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
dma_flags |= DMA_PREP_PQ_DISABLE_Q; dma_flags |= DMA_PREP_PQ_DISABLE_Q;
} else { } else {
pq[1] = dma_map_page(dev, Q(blocks, disks), pq[1] = dma_map_page(dev, Q(blocks, disks),
offset, len, Q(offsets, disks), len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
unmap->addr[j++] = pq[1]; unmap->addr[j++] = pq[1];
unmap->to_cnt++; unmap->to_cnt++;
...@@ -355,7 +372,9 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, ...@@ -355,7 +372,9 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
async_tx_submit(chan, tx, submit); async_tx_submit(chan, tx, submit);
} else { } else {
struct page *p_src = P(blocks, disks); struct page *p_src = P(blocks, disks);
unsigned int p_off = P(offsets, disks);
struct page *q_src = Q(blocks, disks); struct page *q_src = Q(blocks, disks);
unsigned int q_off = Q(offsets, disks);
enum async_tx_flags flags_orig = submit->flags; enum async_tx_flags flags_orig = submit->flags;
dma_async_tx_callback cb_fn_orig = submit->cb_fn; dma_async_tx_callback cb_fn_orig = submit->cb_fn;
void *scribble = submit->scribble; void *scribble = submit->scribble;
...@@ -381,27 +400,32 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, ...@@ -381,27 +400,32 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
if (p_src) { if (p_src) {
init_async_submit(submit, ASYNC_TX_XOR_ZERO_DST, NULL, init_async_submit(submit, ASYNC_TX_XOR_ZERO_DST, NULL,
NULL, NULL, scribble); NULL, NULL, scribble);
tx = async_xor(spare, blocks, offset, disks-2, len, submit); tx = async_xor_offs(spare, s_off,
blocks, offsets, disks-2, len, submit);
async_tx_quiesce(&tx); async_tx_quiesce(&tx);
p = page_address(p_src) + offset; p = page_address(p_src) + p_off;
s = page_address(spare) + offset; s = page_address(spare) + s_off;
*pqres |= !!memcmp(p, s, len) << SUM_CHECK_P; *pqres |= !!memcmp(p, s, len) << SUM_CHECK_P;
} }
if (q_src) { if (q_src) {
P(blocks, disks) = NULL; P(blocks, disks) = NULL;
Q(blocks, disks) = spare; Q(blocks, disks) = spare;
Q(offsets, disks) = s_off;
init_async_submit(submit, 0, NULL, NULL, NULL, scribble); init_async_submit(submit, 0, NULL, NULL, NULL, scribble);
tx = async_gen_syndrome(blocks, offset, disks, len, submit); tx = async_gen_syndrome(blocks, offsets, disks,
len, submit);
async_tx_quiesce(&tx); async_tx_quiesce(&tx);
q = page_address(q_src) + offset; q = page_address(q_src) + q_off;
s = page_address(spare) + offset; s = page_address(spare) + s_off;
*pqres |= !!memcmp(q, s, len) << SUM_CHECK_Q; *pqres |= !!memcmp(q, s, len) << SUM_CHECK_Q;
} }
/* restore P, Q and submit */ /* restore P, Q and submit */
P(blocks, disks) = p_src; P(blocks, disks) = p_src;
P(offsets, disks) = p_off;
Q(blocks, disks) = q_src; Q(blocks, disks) = q_src;
Q(offsets, disks) = q_off;
submit->cb_fn = cb_fn_orig; submit->cb_fn = cb_fn_orig;
submit->cb_param = cb_param_orig; submit->cb_param = cb_param_orig;
......
This diff is collapsed.
...@@ -97,7 +97,8 @@ do_async_xor(struct dma_chan *chan, struct dmaengine_unmap_data *unmap, ...@@ -97,7 +97,8 @@ do_async_xor(struct dma_chan *chan, struct dmaengine_unmap_data *unmap,
} }
static void static void
do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, do_sync_xor_offs(struct page *dest, unsigned int offset,
struct page **src_list, unsigned int *src_offs,
int src_cnt, size_t len, struct async_submit_ctl *submit) int src_cnt, size_t len, struct async_submit_ctl *submit)
{ {
int i; int i;
...@@ -114,7 +115,8 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -114,7 +115,8 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
/* convert to buffer pointers */ /* convert to buffer pointers */
for (i = 0; i < src_cnt; i++) for (i = 0; i < src_cnt; i++)
if (src_list[i]) if (src_list[i])
srcs[xor_src_cnt++] = page_address(src_list[i]) + offset; srcs[xor_src_cnt++] = page_address(src_list[i]) +
(src_offs ? src_offs[i] : offset);
src_cnt = xor_src_cnt; src_cnt = xor_src_cnt;
/* set destination address */ /* set destination address */
dest_buf = page_address(dest) + offset; dest_buf = page_address(dest) + offset;
...@@ -135,11 +137,31 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -135,11 +137,31 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
async_tx_sync_epilog(submit); async_tx_sync_epilog(submit);
} }
static inline bool
dma_xor_aligned_offsets(struct dma_device *device, unsigned int offset,
unsigned int *src_offs, int src_cnt, int len)
{
int i;
if (!is_dma_xor_aligned(device, offset, 0, len))
return false;
if (!src_offs)
return true;
for (i = 0; i < src_cnt; i++) {
if (!is_dma_xor_aligned(device, src_offs[i], 0, len))
return false;
}
return true;
}
/** /**
* async_xor - attempt to xor a set of blocks with a dma engine. * async_xor_offs - attempt to xor a set of blocks with a dma engine.
* @dest: destination page * @dest: destination page
* @offset: dst offset to start transaction
* @src_list: array of source pages * @src_list: array of source pages
* @offset: common src/dst offset to start transaction * @src_offs: array of source pages offset, NULL means common src/dst offset
* @src_cnt: number of source pages * @src_cnt: number of source pages
* @len: length in bytes * @len: length in bytes
* @submit: submission / completion modifiers * @submit: submission / completion modifiers
...@@ -157,7 +179,8 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -157,7 +179,8 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
* is not specified. * is not specified.
*/ */
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_xor(struct page *dest, struct page **src_list, unsigned int offset, async_xor_offs(struct page *dest, unsigned int offset,
struct page **src_list, unsigned int *src_offs,
int src_cnt, size_t len, struct async_submit_ctl *submit) int src_cnt, size_t len, struct async_submit_ctl *submit)
{ {
struct dma_chan *chan = async_tx_find_channel(submit, DMA_XOR, struct dma_chan *chan = async_tx_find_channel(submit, DMA_XOR,
...@@ -171,7 +194,8 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -171,7 +194,8 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
if (device) if (device)
unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOWAIT); unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOWAIT);
if (unmap && is_dma_xor_aligned(device, offset, 0, len)) { if (unmap && dma_xor_aligned_offsets(device, offset,
src_offs, src_cnt, len)) {
struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx;
int i, j; int i, j;
...@@ -184,7 +208,8 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -184,7 +208,8 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
continue; continue;
unmap->to_cnt++; unmap->to_cnt++;
unmap->addr[j++] = dma_map_page(device->dev, src_list[i], unmap->addr[j++] = dma_map_page(device->dev, src_list[i],
offset, len, DMA_TO_DEVICE); src_offs ? src_offs[i] : offset,
len, DMA_TO_DEVICE);
} }
/* map it bidirectional as it may be re-used as a source */ /* map it bidirectional as it may be re-used as a source */
...@@ -213,11 +238,42 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -213,11 +238,42 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
/* wait for any prerequisite operations */ /* wait for any prerequisite operations */
async_tx_quiesce(&submit->depend_tx); async_tx_quiesce(&submit->depend_tx);
do_sync_xor(dest, src_list, offset, src_cnt, len, submit); do_sync_xor_offs(dest, offset, src_list, src_offs,
src_cnt, len, submit);
return NULL; return NULL;
} }
} }
EXPORT_SYMBOL_GPL(async_xor_offs);
/**
* async_xor - attempt to xor a set of blocks with a dma engine.
* @dest: destination page
* @src_list: array of source pages
* @offset: common src/dst offset to start transaction
* @src_cnt: number of source pages
* @len: length in bytes
* @submit: submission / completion modifiers
*
* honored flags: ASYNC_TX_ACK, ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DST
*
* xor_blocks always uses the dest as a source so the
* ASYNC_TX_XOR_ZERO_DST flag must be set to not include dest data in
* the calculation. The assumption with dma eninges is that they only
* use the destination buffer as a source when it is explicity specified
* in the source list.
*
* src_list note: if the dest is also a source it must be at index zero.
* The contents of this array will be overwritten if a scribble region
* is not specified.
*/
struct dma_async_tx_descriptor *
async_xor(struct page *dest, struct page **src_list, unsigned int offset,
int src_cnt, size_t len, struct async_submit_ctl *submit)
{
return async_xor_offs(dest, offset, src_list, NULL,
src_cnt, len, submit);
}
EXPORT_SYMBOL_GPL(async_xor); EXPORT_SYMBOL_GPL(async_xor);
static int page_is_zero(struct page *p, unsigned int offset, size_t len) static int page_is_zero(struct page *p, unsigned int offset, size_t len)
...@@ -237,10 +293,11 @@ xor_val_chan(struct async_submit_ctl *submit, struct page *dest, ...@@ -237,10 +293,11 @@ xor_val_chan(struct async_submit_ctl *submit, struct page *dest,
} }
/** /**
* async_xor_val - attempt a xor parity check with a dma engine. * async_xor_val_offs - attempt a xor parity check with a dma engine.
* @dest: destination page used if the xor is performed synchronously * @dest: destination page used if the xor is performed synchronously
* @offset: des offset in pages to start transaction
* @src_list: array of source pages * @src_list: array of source pages
* @offset: offset in pages to start transaction * @src_offs: array of source pages offset, NULL means common src/det offset
* @src_cnt: number of source pages * @src_cnt: number of source pages
* @len: length in bytes * @len: length in bytes
* @result: 0 if sum == 0 else non-zero * @result: 0 if sum == 0 else non-zero
...@@ -253,7 +310,8 @@ xor_val_chan(struct async_submit_ctl *submit, struct page *dest, ...@@ -253,7 +310,8 @@ xor_val_chan(struct async_submit_ctl *submit, struct page *dest,
* is not specified. * is not specified.
*/ */
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, async_xor_val_offs(struct page *dest, unsigned int offset,
struct page **src_list, unsigned int *src_offs,
int src_cnt, size_t len, enum sum_check_flags *result, int src_cnt, size_t len, enum sum_check_flags *result,
struct async_submit_ctl *submit) struct async_submit_ctl *submit)
{ {
...@@ -268,7 +326,7 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -268,7 +326,7 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOWAIT); unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOWAIT);
if (unmap && src_cnt <= device->max_xor && if (unmap && src_cnt <= device->max_xor &&
is_dma_xor_aligned(device, offset, 0, len)) { dma_xor_aligned_offsets(device, offset, src_offs, src_cnt, len)) {
unsigned long dma_prep_flags = 0; unsigned long dma_prep_flags = 0;
int i; int i;
...@@ -281,7 +339,8 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -281,7 +339,8 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
for (i = 0; i < src_cnt; i++) { for (i = 0; i < src_cnt; i++) {
unmap->addr[i] = dma_map_page(device->dev, src_list[i], unmap->addr[i] = dma_map_page(device->dev, src_list[i],
offset, len, DMA_TO_DEVICE); src_offs ? src_offs[i] : offset,
len, DMA_TO_DEVICE);
unmap->to_cnt++; unmap->to_cnt++;
} }
unmap->len = len; unmap->len = len;
...@@ -312,7 +371,8 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -312,7 +371,8 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
submit->flags |= ASYNC_TX_XOR_DROP_DST; submit->flags |= ASYNC_TX_XOR_DROP_DST;
submit->flags &= ~ASYNC_TX_ACK; submit->flags &= ~ASYNC_TX_ACK;
tx = async_xor(dest, src_list, offset, src_cnt, len, submit); tx = async_xor_offs(dest, offset, src_list, src_offs,
src_cnt, len, submit);
async_tx_quiesce(&tx); async_tx_quiesce(&tx);
...@@ -325,6 +385,32 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -325,6 +385,32 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
return tx; return tx;
} }
EXPORT_SYMBOL_GPL(async_xor_val_offs);
/**
* async_xor_val - attempt a xor parity check with a dma engine.
* @dest: destination page used if the xor is performed synchronously
* @src_list: array of source pages
* @offset: offset in pages to start transaction
* @src_cnt: number of source pages
* @len: length in bytes
* @result: 0 if sum == 0 else non-zero
* @submit: submission / completion modifiers
*
* honored flags: ASYNC_TX_ACK
*
* src_list note: if the dest is also a source it must be at index zero.
* The contents of this array will be overwritten if a scribble region
* is not specified.
*/
struct dma_async_tx_descriptor *
async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
int src_cnt, size_t len, enum sum_check_flags *result,
struct async_submit_ctl *submit)
{
return async_xor_val_offs(dest, offset, src_list, NULL, src_cnt,
len, result, submit);
}
EXPORT_SYMBOL_GPL(async_xor_val); EXPORT_SYMBOL_GPL(async_xor_val);
MODULE_AUTHOR("Intel Corporation"); MODULE_AUTHOR("Intel Corporation");
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define NDISKS 64 /* Including P and Q */ #define NDISKS 64 /* Including P and Q */
static struct page *dataptrs[NDISKS]; static struct page *dataptrs[NDISKS];
unsigned int dataoffs[NDISKS];
static addr_conv_t addr_conv[NDISKS]; static addr_conv_t addr_conv[NDISKS];
static struct page *data[NDISKS+3]; static struct page *data[NDISKS+3];
static struct page *spare; static struct page *spare;
...@@ -38,6 +39,7 @@ static void makedata(int disks) ...@@ -38,6 +39,7 @@ static void makedata(int disks)
for (i = 0; i < disks; i++) { for (i = 0; i < disks; i++) {
prandom_bytes(page_address(data[i]), PAGE_SIZE); prandom_bytes(page_address(data[i]), PAGE_SIZE);
dataptrs[i] = data[i]; dataptrs[i] = data[i];
dataoffs[i] = 0;
} }
} }
...@@ -52,7 +54,8 @@ static char disk_type(int d, int disks) ...@@ -52,7 +54,8 @@ static char disk_type(int d, int disks)
} }
/* Recover two failed blocks. */ /* Recover two failed blocks. */
static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, struct page **ptrs) static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
struct page **ptrs, unsigned int *offs)
{ {
struct async_submit_ctl submit; struct async_submit_ctl submit;
struct completion cmp; struct completion cmp;
...@@ -66,7 +69,8 @@ static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, stru ...@@ -66,7 +69,8 @@ static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, stru
if (faila == disks-2) { if (faila == disks-2) {
/* P+Q failure. Just rebuild the syndrome. */ /* P+Q failure. Just rebuild the syndrome. */
init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv); init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv);
tx = async_gen_syndrome(ptrs, 0, disks, bytes, &submit); tx = async_gen_syndrome(ptrs, offs,
disks, bytes, &submit);
} else { } else {
struct page *blocks[NDISKS]; struct page *blocks[NDISKS];
struct page *dest; struct page *dest;
...@@ -89,22 +93,26 @@ static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, stru ...@@ -89,22 +93,26 @@ static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, stru
tx = async_xor(dest, blocks, 0, count, bytes, &submit); tx = async_xor(dest, blocks, 0, count, bytes, &submit);
init_async_submit(&submit, 0, tx, NULL, NULL, addr_conv); init_async_submit(&submit, 0, tx, NULL, NULL, addr_conv);
tx = async_gen_syndrome(ptrs, 0, disks, bytes, &submit); tx = async_gen_syndrome(ptrs, offs,
disks, bytes, &submit);
} }
} else { } else {
if (failb == disks-2) { if (failb == disks-2) {
/* data+P failure. */ /* data+P failure. */
init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv); init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv);
tx = async_raid6_datap_recov(disks, bytes, faila, ptrs, &submit); tx = async_raid6_datap_recov(disks, bytes,
faila, ptrs, offs, &submit);
} else { } else {
/* data+data failure. */ /* data+data failure. */
init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv); init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv);
tx = async_raid6_2data_recov(disks, bytes, faila, failb, ptrs, &submit); tx = async_raid6_2data_recov(disks, bytes,
faila, failb, ptrs, offs, &submit);
} }
} }
init_completion(&cmp); init_completion(&cmp);
init_async_submit(&submit, ASYNC_TX_ACK, tx, callback, &cmp, addr_conv); init_async_submit(&submit, ASYNC_TX_ACK, tx, callback, &cmp, addr_conv);
tx = async_syndrome_val(ptrs, 0, disks, bytes, &result, spare, &submit); tx = async_syndrome_val(ptrs, offs,
disks, bytes, &result, spare, 0, &submit);
async_tx_issue_pending(tx); async_tx_issue_pending(tx);
if (wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)) == 0) if (wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)) == 0)
...@@ -126,7 +134,7 @@ static int test_disks(int i, int j, int disks) ...@@ -126,7 +134,7 @@ static int test_disks(int i, int j, int disks)
dataptrs[i] = recovi; dataptrs[i] = recovi;
dataptrs[j] = recovj; dataptrs[j] = recovj;
raid6_dual_recov(disks, PAGE_SIZE, i, j, dataptrs); raid6_dual_recov(disks, PAGE_SIZE, i, j, dataptrs, dataoffs);
erra = memcmp(page_address(data[i]), page_address(recovi), PAGE_SIZE); erra = memcmp(page_address(data[i]), page_address(recovi), PAGE_SIZE);
errb = memcmp(page_address(data[j]), page_address(recovj), PAGE_SIZE); errb = memcmp(page_address(data[j]), page_address(recovj), PAGE_SIZE);
...@@ -162,7 +170,7 @@ static int test(int disks, int *tests) ...@@ -162,7 +170,7 @@ static int test(int disks, int *tests)
/* Generate assumed good syndrome */ /* Generate assumed good syndrome */
init_completion(&cmp); init_completion(&cmp);
init_async_submit(&submit, ASYNC_TX_ACK, NULL, callback, &cmp, addr_conv); init_async_submit(&submit, ASYNC_TX_ACK, NULL, callback, &cmp, addr_conv);
tx = async_gen_syndrome(dataptrs, 0, disks, PAGE_SIZE, &submit); tx = async_gen_syndrome(dataptrs, dataoffs, disks, PAGE_SIZE, &submit);
async_tx_issue_pending(tx); async_tx_issue_pending(tx);
if (wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)) == 0) { if (wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)) == 0) {
......
...@@ -357,11 +357,12 @@ static int read_page(struct file *file, unsigned long index, ...@@ -357,11 +357,12 @@ static int read_page(struct file *file, unsigned long index,
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct buffer_head *bh; struct buffer_head *bh;
sector_t block, blk_cur; sector_t block, blk_cur;
unsigned long blocksize = i_blocksize(inode);
pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE, pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT); (unsigned long long)index << PAGE_SHIFT);
bh = alloc_page_buffers(page, 1<<inode->i_blkbits, false); bh = alloc_page_buffers(page, blocksize, false);
if (!bh) { if (!bh) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
...@@ -383,10 +384,10 @@ static int read_page(struct file *file, unsigned long index, ...@@ -383,10 +384,10 @@ static int read_page(struct file *file, unsigned long index,
bh->b_blocknr = block; bh->b_blocknr = block;
bh->b_bdev = inode->i_sb->s_bdev; bh->b_bdev = inode->i_sb->s_bdev;
if (count < (1<<inode->i_blkbits)) if (count < blocksize)
count = 0; count = 0;
else else
count -= (1<<inode->i_blkbits); count -= blocksize;
bh->b_end_io = end_bitmap_write; bh->b_end_io = end_bitmap_write;
bh->b_private = bitmap; bh->b_private = bitmap;
......
...@@ -8583,6 +8583,26 @@ void md_write_end(struct mddev *mddev) ...@@ -8583,6 +8583,26 @@ void md_write_end(struct mddev *mddev)
EXPORT_SYMBOL(md_write_end); EXPORT_SYMBOL(md_write_end);
/* This is used by raid0 and raid10 */
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
struct bio *bio, sector_t start, sector_t size)
{
struct bio *discard_bio = NULL;
if (__blkdev_issue_discard(rdev->bdev, start, size,
GFP_NOIO, 0, &discard_bio) || !discard_bio)
return;
bio_chain(discard_bio, bio);
bio_clone_blkg_association(discard_bio, bio);
if (mddev->gendisk)
trace_block_bio_remap(bdev_get_queue(rdev->bdev),
discard_bio, disk_devt(mddev->gendisk),
bio->bi_iter.bi_sector);
submit_bio_noacct(discard_bio);
}
EXPORT_SYMBOL(md_submit_discard_bio);
/* md_allow_write(mddev) /* md_allow_write(mddev)
* Calling this ensures that the array is marked 'active' so that writes * Calling this ensures that the array is marked 'active' so that writes
* may proceed without blocking. It is important to call this before * may proceed without blocking. It is important to call this before
......
...@@ -713,6 +713,8 @@ extern void md_write_end(struct mddev *mddev); ...@@ -713,6 +713,8 @@ extern void md_write_end(struct mddev *mddev);
extern void md_done_sync(struct mddev *mddev, int blocks, int ok); extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
extern void md_error(struct mddev *mddev, struct md_rdev *rdev); extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
extern void md_finish_reshape(struct mddev *mddev); extern void md_finish_reshape(struct mddev *mddev);
extern void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
struct bio *bio, sector_t start, sector_t size);
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio); extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev, extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
......
...@@ -494,7 +494,6 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) ...@@ -494,7 +494,6 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
for (disk = 0; disk < zone->nb_dev; disk++) { for (disk = 0; disk < zone->nb_dev; disk++) {
sector_t dev_start, dev_end; sector_t dev_start, dev_end;
struct bio *discard_bio = NULL;
struct md_rdev *rdev; struct md_rdev *rdev;
if (disk < start_disk_index) if (disk < start_disk_index)
...@@ -517,18 +516,9 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) ...@@ -517,18 +516,9 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
rdev = conf->devlist[(zone - conf->strip_zone) * rdev = conf->devlist[(zone - conf->strip_zone) *
conf->strip_zone[0].nb_dev + disk]; conf->strip_zone[0].nb_dev + disk];
if (__blkdev_issue_discard(rdev->bdev, md_submit_discard_bio(mddev, rdev, bio,
dev_start + zone->dev_start + rdev->data_offset, dev_start + zone->dev_start + rdev->data_offset,
dev_end - dev_start, GFP_NOIO, 0, &discard_bio) || dev_end - dev_start);
!discard_bio)
continue;
bio_chain(discard_bio, bio);
bio_clone_blkg_association(discard_bio, bio);
if (mddev->gendisk)
trace_block_bio_remap(bdev_get_queue(rdev->bdev),
discard_bio, disk_devt(mddev->gendisk),
bio->bi_iter.bi_sector);
submit_bio_noacct(discard_bio);
} }
bio_endio(bio); bio_endio(bio);
} }
......
This diff is collapsed.
...@@ -179,5 +179,6 @@ enum r10bio_state { ...@@ -179,5 +179,6 @@ enum r10bio_state {
R10BIO_Previous, R10BIO_Previous,
/* failfast devices did receive failfast requests. */ /* failfast devices did receive failfast requests. */
R10BIO_FailFast, R10BIO_FailFast,
R10BIO_Discard,
}; };
#endif #endif
This diff is collapsed.
...@@ -195,6 +195,7 @@ enum reconstruct_states { ...@@ -195,6 +195,7 @@ enum reconstruct_states {
reconstruct_state_result, reconstruct_state_result,
}; };
#define DEFAULT_STRIPE_SIZE 4096
struct stripe_head { struct stripe_head {
struct hlist_node hash; struct hlist_node hash;
struct list_head lru; /* inactive_list or handle_list */ struct list_head lru; /* inactive_list or handle_list */
...@@ -246,6 +247,13 @@ struct stripe_head { ...@@ -246,6 +247,13 @@ struct stripe_head {
int target, target2; int target, target2;
enum sum_check_flags zero_sum_result; enum sum_check_flags zero_sum_result;
} ops; } ops;
#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
/* These pages will be used by bios in dev[i] */
struct page **pages;
int nr_pages; /* page array size */
int stripes_per_page;
#endif
struct r5dev { struct r5dev {
/* rreq and rvec are used for the replacement device when /* rreq and rvec are used for the replacement device when
* writing data to both devices. * writing data to both devices.
...@@ -253,6 +261,7 @@ struct stripe_head { ...@@ -253,6 +261,7 @@ struct stripe_head {
struct bio req, rreq; struct bio req, rreq;
struct bio_vec vec, rvec; struct bio_vec vec, rvec;
struct page *page, *orig_page; struct page *page, *orig_page;
unsigned int offset; /* offset of the page */
struct bio *toread, *read, *towrite, *written; struct bio *toread, *read, *towrite, *written;
sector_t sector; /* sector of this page */ sector_t sector; /* sector of this page */
unsigned long flags; unsigned long flags;
...@@ -472,7 +481,6 @@ struct disk_info { ...@@ -472,7 +481,6 @@ struct disk_info {
*/ */
#define NR_STRIPES 256 #define NR_STRIPES 256
#define DEFAULT_STRIPE_SIZE 4096
#if PAGE_SIZE == DEFAULT_STRIPE_SIZE #if PAGE_SIZE == DEFAULT_STRIPE_SIZE
#define STRIPE_SIZE PAGE_SIZE #define STRIPE_SIZE PAGE_SIZE
...@@ -771,6 +779,25 @@ static inline int algorithm_is_DDF(int layout) ...@@ -771,6 +779,25 @@ static inline int algorithm_is_DDF(int layout)
return layout >= 8 && layout <= 10; return layout >= 8 && layout <= 10;
} }
#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
/*
* Return offset of the corresponding page for r5dev.
*/
static inline int raid5_get_page_offset(struct stripe_head *sh, int disk_idx)
{
return (disk_idx % sh->stripes_per_page) * RAID5_STRIPE_SIZE(sh->raid_conf);
}
/*
* Return corresponding page address for r5dev.
*/
static inline struct page *
raid5_get_dev_page(struct stripe_head *sh, int disk_idx)
{
return sh->pages[disk_idx / sh->stripes_per_page];
}
#endif
extern void md_raid5_kick_device(struct r5conf *conf); extern void md_raid5_kick_device(struct r5conf *conf);
extern int raid5_set_cache_size(struct mddev *mddev, int size); extern int raid5_set_cache_size(struct mddev *mddev, int size);
extern sector_t raid5_compute_blocknr(struct stripe_head *sh, int i, int previous); extern sector_t raid5_compute_blocknr(struct stripe_head *sh, int i, int previous);
......
...@@ -162,11 +162,22 @@ struct dma_async_tx_descriptor * ...@@ -162,11 +162,22 @@ struct dma_async_tx_descriptor *
async_xor(struct page *dest, struct page **src_list, unsigned int offset, async_xor(struct page *dest, struct page **src_list, unsigned int offset,
int src_cnt, size_t len, struct async_submit_ctl *submit); int src_cnt, size_t len, struct async_submit_ctl *submit);
struct dma_async_tx_descriptor *
async_xor_offs(struct page *dest, unsigned int offset,
struct page **src_list, unsigned int *src_offset,
int src_cnt, size_t len, struct async_submit_ctl *submit);
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
int src_cnt, size_t len, enum sum_check_flags *result, int src_cnt, size_t len, enum sum_check_flags *result,
struct async_submit_ctl *submit); struct async_submit_ctl *submit);
struct dma_async_tx_descriptor *
async_xor_val_offs(struct page *dest, unsigned int offset,
struct page **src_list, unsigned int *src_offset,
int src_cnt, size_t len, enum sum_check_flags *result,
struct async_submit_ctl *submit);
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
unsigned int src_offset, size_t len, unsigned int src_offset, size_t len,
...@@ -175,21 +186,23 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, ...@@ -175,21 +186,23 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
struct dma_async_tx_descriptor *async_trigger_callback(struct async_submit_ctl *submit); struct dma_async_tx_descriptor *async_trigger_callback(struct async_submit_ctl *submit);
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_gen_syndrome(struct page **blocks, unsigned int offset, int src_cnt, async_gen_syndrome(struct page **blocks, unsigned int *offsets, int src_cnt,
size_t len, struct async_submit_ctl *submit); size_t len, struct async_submit_ctl *submit);
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_syndrome_val(struct page **blocks, unsigned int offset, int src_cnt, async_syndrome_val(struct page **blocks, unsigned int *offsets, int src_cnt,
size_t len, enum sum_check_flags *pqres, struct page *spare, size_t len, enum sum_check_flags *pqres, struct page *spare,
struct async_submit_ctl *submit); unsigned int s_off, struct async_submit_ctl *submit);
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_raid6_2data_recov(int src_num, size_t bytes, int faila, int failb, async_raid6_2data_recov(int src_num, size_t bytes, int faila, int failb,
struct page **ptrs, struct async_submit_ctl *submit); struct page **ptrs, unsigned int *offs,
struct async_submit_ctl *submit);
struct dma_async_tx_descriptor * struct dma_async_tx_descriptor *
async_raid6_datap_recov(int src_num, size_t bytes, int faila, async_raid6_datap_recov(int src_num, size_t bytes, int faila,
struct page **ptrs, struct async_submit_ctl *submit); struct page **ptrs, unsigned int *offs,
struct async_submit_ctl *submit);
void async_tx_quiesce(struct dma_async_tx_descriptor **tx); void async_tx_quiesce(struct dma_async_tx_descriptor **tx);
#endif /* _ASYNC_TX_H_ */ #endif /* _ASYNC_TX_H_ */
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