aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Stockhausen <stockhausen@collogia.de>2014-12-14 20:57:05 -0500
committerNeilBrown <neilb@suse.de>2015-04-21 18:00:42 -0400
commit584acdd49cd2472ca0f5a06adbe979db82d0b4af (patch)
tree94abdc5ca0208e47275bc2a8ad82c2d25cefddfd
parenta582564b24bec0443b5c5ff43ee6d1258f8bd658 (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.c19
-rw-r--r--drivers/md/raid5.c104
-rw-r--r--drivers/md/raid5.h19
-rw-r--r--include/linux/async_tx.h3
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 */
1320static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh) 1320static 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
1517static struct dma_async_tx_descriptor * 1526static struct dma_async_tx_descriptor *
1518ops_run_prexor(struct stripe_head *sh, struct raid5_percpu *percpu, 1527ops_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
1547static struct dma_async_tx_descriptor * 1556static struct dma_async_tx_descriptor *
1557ops_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
1576static struct dma_async_tx_descriptor *
1548ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) 1577ops_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
1766again: 1797again:
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