diff options
| author | Markus Stockhausen <stockhausen@collogia.de> | 2014-12-14 20:57:05 -0500 |
|---|---|---|
| committer | NeilBrown <neilb@suse.de> | 2015-04-21 18:00:42 -0400 |
| commit | 584acdd49cd2472ca0f5a06adbe979db82d0b4af (patch) | |
| tree | 94abdc5ca0208e47275bc2a8ad82c2d25cefddfd | |
| parent | a582564b24bec0443b5c5ff43ee6d1258f8bd658 (diff) | |
md/raid5: activate raid6 rmw feature
Glue it altogehter. The raid6 rmw path should work the same as the
already existing raid5 logic. So emulate the prexor handling/flags
and split functions as needed.
1) Enable xor_syndrome() in the async layer.
2) Split ops_run_prexor() into RAID4/5 and RAID6 logic. Xor the syndrome
at the start of a rmw run as we did it before for the single parity.
3) Take care of rmw run in ops_run_reconstruct6(). Again process only
the changed pages to get syndrome back into sync.
4) Enhance set_syndrome_sources() to fill NULL pages if we are in a rmw
run. The lower layers will calculate start & end pages from that and
call the xor_syndrome() correspondingly.
5) Adapt the several places where we ignored Q handling up to now.
Performance numbers for a single E5630 system with a mix of 10 7200k
desktop/server disks. 300 seconds random write with 8 threads onto a
3,2TB (10*400GB) RAID6 64K chunk without spare (group_thread_cnt=4)
bsize rmw_level=1 rmw_level=0 rmw_level=1 rmw_level=0
skip_copy=1 skip_copy=1 skip_copy=0 skip_copy=0
4K 115 KB/s 141 KB/s 165 KB/s 140 KB/s
8K 225 KB/s 275 KB/s 324 KB/s 274 KB/s
16K 434 KB/s 536 KB/s 640 KB/s 534 KB/s
32K 751 KB/s 1,051 KB/s 1,234 KB/s 1,045 KB/s
64K 1,339 KB/s 1,958 KB/s 2,282 KB/s 1,962 KB/s
128K 2,673 KB/s 3,862 KB/s 4,113 KB/s 3,898 KB/s
256K 7,685 KB/s 7,539 KB/s 7,557 KB/s 7,638 KB/s
512K 19,556 KB/s 19,558 KB/s 19,652 KB/s 19,688 Kb/s
Signed-off-by: Markus Stockhausen <stockhausen@collogia.de>
Signed-off-by: NeilBrown <neilb@suse.de>
| -rw-r--r-- | crypto/async_tx/async_pq.c | 19 | ||||
| -rw-r--r-- | drivers/md/raid5.c | 104 | ||||
| -rw-r--r-- | drivers/md/raid5.h | 19 | ||||
| -rw-r--r-- | include/linux/async_tx.h | 3 |
4 files changed, 115 insertions, 30 deletions
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c index d05327caf69d..5d355e0c2633 100644 --- a/crypto/async_tx/async_pq.c +++ b/crypto/async_tx/async_pq.c | |||
| @@ -124,6 +124,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, | |||
| 124 | { | 124 | { |
| 125 | void **srcs; | 125 | void **srcs; |
| 126 | int i; | 126 | int i; |
| 127 | int start = -1, stop = disks - 3; | ||
| 127 | 128 | ||
| 128 | if (submit->scribble) | 129 | if (submit->scribble) |
| 129 | srcs = submit->scribble; | 130 | srcs = submit->scribble; |
| @@ -134,10 +135,21 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, | |||
| 134 | if (blocks[i] == NULL) { | 135 | if (blocks[i] == NULL) { |
| 135 | BUG_ON(i > disks - 3); /* P or Q can't be zero */ | 136 | BUG_ON(i > disks - 3); /* P or Q can't be zero */ |
| 136 | srcs[i] = (void*)raid6_empty_zero_page; | 137 | srcs[i] = (void*)raid6_empty_zero_page; |
| 137 | } else | 138 | } else { |
| 138 | srcs[i] = page_address(blocks[i]) + offset; | 139 | srcs[i] = page_address(blocks[i]) + offset; |
| 140 | if (i < disks - 2) { | ||
| 141 | stop = i; | ||
| 142 | if (start == -1) | ||
| 143 | start = i; | ||
| 144 | } | ||
| 145 | } | ||
| 139 | } | 146 | } |
| 140 | raid6_call.gen_syndrome(disks, len, srcs); | 147 | if (submit->flags & ASYNC_TX_PQ_XOR_DST) { |
| 148 | BUG_ON(!raid6_call.xor_syndrome); | ||
| 149 | if (start >= 0) | ||
| 150 | raid6_call.xor_syndrome(disks, start, stop, len, srcs); | ||
| 151 | } else | ||
| 152 | raid6_call.gen_syndrome(disks, len, srcs); | ||
| 141 | async_tx_sync_epilog(submit); | 153 | async_tx_sync_epilog(submit); |
| 142 | } | 154 | } |
| 143 | 155 | ||
| @@ -178,7 +190,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, | |||
| 178 | if (device) | 190 | if (device) |
| 179 | unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO); | 191 | unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO); |
| 180 | 192 | ||
| 181 | if (unmap && | 193 | /* XORing P/Q is only implemented in software */ |
| 194 | if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) && | ||
| 182 | (src_cnt <= dma_maxpq(device, 0) || | 195 | (src_cnt <= dma_maxpq(device, 0) || |
| 183 | dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && | 196 | dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && |
| 184 | is_dma_pq_aligned(device, offset, 0, len)) { | 197 | is_dma_pq_aligned(device, offset, 0, len)) { |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3ae097d50b51..c82ce1fd8723 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -1317,7 +1317,9 @@ ops_run_compute5(struct stripe_head *sh, struct raid5_percpu *percpu) | |||
| 1317 | * destination buffer is recorded in srcs[count] and the Q destination | 1317 | * destination buffer is recorded in srcs[count] and the Q destination |
| 1318 | * is recorded in srcs[count+1]]. | 1318 | * is recorded in srcs[count+1]]. |
| 1319 | */ | 1319 | */ |
| 1320 | static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh) | 1320 | static int set_syndrome_sources(struct page **srcs, |
| 1321 | struct stripe_head *sh, | ||
| 1322 | int srctype) | ||
| 1321 | { | 1323 | { |
| 1322 | int disks = sh->disks; | 1324 | int disks = sh->disks; |
| 1323 | int syndrome_disks = sh->ddf_layout ? disks : (disks - 2); | 1325 | int syndrome_disks = sh->ddf_layout ? disks : (disks - 2); |
| @@ -1332,8 +1334,15 @@ static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh) | |||
| 1332 | i = d0_idx; | 1334 | i = d0_idx; |
| 1333 | do { | 1335 | do { |
| 1334 | int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); | 1336 | int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); |
| 1337 | struct r5dev *dev = &sh->dev[i]; | ||
| 1335 | 1338 | ||
| 1336 | srcs[slot] = sh->dev[i].page; | 1339 | if (i == sh->qd_idx || i == sh->pd_idx || |
| 1340 | (srctype == SYNDROME_SRC_ALL) || | ||
| 1341 | (srctype == SYNDROME_SRC_WANT_DRAIN && | ||
| 1342 | test_bit(R5_Wantdrain, &dev->flags)) || | ||
| 1343 | (srctype == SYNDROME_SRC_WRITTEN && | ||
| 1344 | dev->written)) | ||
| 1345 | srcs[slot] = sh->dev[i].page; | ||
| 1337 | i = raid6_next_disk(i, disks); | 1346 | i = raid6_next_disk(i, disks); |
| 1338 | } while (i != d0_idx); | 1347 | } while (i != d0_idx); |
| 1339 | 1348 | ||
| @@ -1373,7 +1382,7 @@ ops_run_compute6_1(struct stripe_head *sh, struct raid5_percpu *percpu) | |||
| 1373 | atomic_inc(&sh->count); | 1382 | atomic_inc(&sh->count); |
| 1374 | 1383 | ||
| 1375 | if (target == qd_idx) { | 1384 | if (target == qd_idx) { |
| 1376 | count = set_syndrome_sources(blocks, sh); | 1385 | count = set_syndrome_sources(blocks, sh, SYNDROME_SRC_ALL); |
| 1377 | blocks[count] = NULL; /* regenerating p is not necessary */ | 1386 | blocks[count] = NULL; /* regenerating p is not necessary */ |
| 1378 | BUG_ON(blocks[count+1] != dest); /* q should already be set */ | 1387 | BUG_ON(blocks[count+1] != dest); /* q should already be set */ |
| 1379 | init_async_submit(&submit, ASYNC_TX_FENCE, NULL, | 1388 | init_async_submit(&submit, ASYNC_TX_FENCE, NULL, |
| @@ -1481,7 +1490,7 @@ ops_run_compute6_2(struct stripe_head *sh, struct raid5_percpu *percpu) | |||
| 1481 | tx = async_xor(dest, blocks, 0, count, STRIPE_SIZE, | 1490 | tx = async_xor(dest, blocks, 0, count, STRIPE_SIZE, |
| 1482 | &submit); | 1491 | &submit); |
| 1483 | 1492 | ||
| 1484 | count = set_syndrome_sources(blocks, sh); | 1493 | count = set_syndrome_sources(blocks, sh, SYNDROME_SRC_ALL); |
| 1485 | init_async_submit(&submit, ASYNC_TX_FENCE, tx, | 1494 | init_async_submit(&submit, ASYNC_TX_FENCE, tx, |
| 1486 | ops_complete_compute, sh, | 1495 | ops_complete_compute, sh, |
| 1487 | to_addr_conv(sh, percpu, 0)); | 1496 | to_addr_conv(sh, percpu, 0)); |
| @@ -1515,8 +1524,8 @@ static void ops_complete_prexor(void *stripe_head_ref) | |||
| 1515 | } | 1524 | } |
| 1516 | 1525 | ||
| 1517 | static struct dma_async_tx_descriptor * | 1526 | static struct dma_async_tx_descriptor * |
| 1518 | ops_run_prexor(struct stripe_head *sh, struct raid5_percpu *percpu, | 1527 | ops_run_prexor5(struct stripe_head *sh, struct raid5_percpu *percpu, |
| 1519 | struct dma_async_tx_descriptor *tx) | 1528 | struct dma_async_tx_descriptor *tx) |
| 1520 | { | 1529 | { |
| 1521 | int disks = sh->disks; | 1530 | int disks = sh->disks; |
| 1522 | struct page **xor_srcs = to_addr_page(percpu, 0); | 1531 | struct page **xor_srcs = to_addr_page(percpu, 0); |
| @@ -1545,6 +1554,26 @@ ops_run_prexor(struct stripe_head *sh, struct raid5_percpu *percpu, | |||
| 1545 | } | 1554 | } |
| 1546 | 1555 | ||
| 1547 | static struct dma_async_tx_descriptor * | 1556 | static struct dma_async_tx_descriptor * |
| 1557 | ops_run_prexor6(struct stripe_head *sh, struct raid5_percpu *percpu, | ||
| 1558 | struct dma_async_tx_descriptor *tx) | ||
| 1559 | { | ||
| 1560 | struct page **blocks = to_addr_page(percpu, 0); | ||
| 1561 | int count; | ||
| 1562 | struct async_submit_ctl submit; | ||
| 1563 | |||
| 1564 | pr_debug("%s: stripe %llu\n", __func__, | ||
| 1565 | (unsigned long long)sh->sector); | ||
| 1566 | |||
| 1567 | count = set_syndrome_sources(blocks, sh, SYNDROME_SRC_WANT_DRAIN); | ||
| 1568 | |||
| 1569 | init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_PQ_XOR_DST, tx, | ||
| 1570 | ops_complete_prexor, sh, to_addr_conv(sh, percpu, 0)); | ||
| 1571 | tx = async_gen_syndrome(blocks, 0, count+2, STRIPE_SIZE, &submit); | ||
| 1572 | |||
| 1573 | return tx; | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | static struct dma_async_tx_descriptor * | ||
| 1548 | ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) | 1577 | ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) |
| 1549 | { | 1578 | { |
| 1550 | int disks = sh->disks; | 1579 | int disks = sh->disks; |
| @@ -1746,6 +1775,8 @@ ops_run_reconstruct6(struct stripe_head *sh, struct raid5_percpu *percpu, | |||
| 1746 | int count, i, j = 0; | 1775 | int count, i, j = 0; |
| 1747 | struct stripe_head *head_sh = sh; | 1776 | struct stripe_head *head_sh = sh; |
| 1748 | int last_stripe; | 1777 | int last_stripe; |
| 1778 | int synflags; | ||
| 1779 | unsigned long txflags; | ||
| 1749 | 1780 | ||
| 1750 | pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); | 1781 | pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); |
| 1751 | 1782 | ||
| @@ -1765,14 +1796,23 @@ ops_run_reconstruct6(struct stripe_head *sh, struct raid5_percpu *percpu, | |||
| 1765 | 1796 | ||
| 1766 | again: | 1797 | again: |
| 1767 | blocks = to_addr_page(percpu, j); | 1798 | blocks = to_addr_page(percpu, j); |
| 1768 | count = set_syndrome_sources(blocks, sh); | 1799 | |
| 1800 | if (sh->reconstruct_state == reconstruct_state_prexor_drain_run) { | ||
| 1801 | synflags = SYNDROME_SRC_WRITTEN; | ||
| 1802 | txflags = ASYNC_TX_ACK | ASYNC_TX_PQ_XOR_DST; | ||
| 1803 | } else { | ||
| 1804 | synflags = SYNDROME_SRC_ALL; | ||
| 1805 | txflags = ASYNC_TX_ACK; | ||
| 1806 | } | ||
| 1807 | |||
| 1808 | count = set_syndrome_sources(blocks, sh, synflags); | ||
| 1769 | last_stripe = !head_sh->batch_head || | 1809 | last_stripe = !head_sh->batch_head || |
| 1770 | list_first_entry(&sh->batch_list, | 1810 | list_first_entry(&sh->batch_list, |
| 1771 | struct stripe_head, batch_list) == head_sh; | 1811 | struct stripe_head, batch_list) == he |
