linux-raid.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dan Williams <dan.j.williams@intel.com>
To: neilb@suse.de, linux-raid@vger.kernel.org
Cc: maan@systemlinux.org, linux-kernel@vger.kernel.org,
	yur@emcraft.com, hpa@zytor.com
Subject: [PATCH v2 09/11] async_tx: add support for asynchronous RAID6 recovery operations
Date: Mon, 18 May 2009 18:00:12 -0700	[thread overview]
Message-ID: <20090519010012.4104.50825.stgit@dwillia2-linux.ch.intel.com> (raw)
In-Reply-To: <20090519005647.4104.81119.stgit@dwillia2-linux.ch.intel.com>

 async_raid6_2data_recov() recovers two data disk failures

 async_raid6_datap_recov() recovers a data disk and the P disk

These routines are a port of the synchronous versions found in
drivers/md/raid6recov.c.  The primary difference is breaking out the xor
operations into separate calls to async_xor.  Two helper routines are
introduced to perform scalar multiplication where needed.
async_sum_product() multiplies two sources by scalar coefficients and
then sums (xor) the result.  async_mult() simply multiplies a single
source by a scalar.

[ Impact: asynchronous raid6 recovery routines for 2data and datap cases ]

Cc: Yuri Tikhonov <yur@emcraft.com>
Cc: Ilya Yanok <yanok@emcraft.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 crypto/async_tx/Kconfig             |    5 +
 crypto/async_tx/Makefile            |    1 
 crypto/async_tx/async_raid6_recov.c |  292 +++++++++++++++++++++++++++++++++++
 include/linux/async_tx.h            |    8 +
 4 files changed, 306 insertions(+), 0 deletions(-)
 create mode 100644 crypto/async_tx/async_raid6_recov.c

diff --git a/crypto/async_tx/Kconfig b/crypto/async_tx/Kconfig
index cb6d731..e5aeb2b 100644
--- a/crypto/async_tx/Kconfig
+++ b/crypto/async_tx/Kconfig
@@ -18,3 +18,8 @@ config ASYNC_PQ
 	tristate
 	select ASYNC_CORE
 
+config ASYNC_RAID6_RECOV
+	tristate
+	select ASYNC_CORE
+	select ASYNC_PQ
+
diff --git a/crypto/async_tx/Makefile b/crypto/async_tx/Makefile
index 1b99265..9a1a768 100644
--- a/crypto/async_tx/Makefile
+++ b/crypto/async_tx/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_ASYNC_MEMCPY) += async_memcpy.o
 obj-$(CONFIG_ASYNC_MEMSET) += async_memset.o
 obj-$(CONFIG_ASYNC_XOR) += async_xor.o
 obj-$(CONFIG_ASYNC_PQ) += async_pq.o
+obj-$(CONFIG_ASYNC_RAID6_RECOV) += async_raid6_recov.o
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
new file mode 100644
index 0000000..ea019e8
--- /dev/null
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -0,0 +1,292 @@
+/*
+ * Asynchronous RAID-6 recovery calculations ASYNC_TX API.
+ * Copyright(c) 2009 Intel Corporation
+ *
+ * based on raid6recov.c:
+ *   Copyright 2002 H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/raid/pq.h>
+#include <linux/async_tx.h>
+
+static struct dma_async_tx_descriptor *
+async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
+		  size_t len, struct async_submit_ctl *submit)
+{
+	struct dma_chan *chan = async_tx_find_channel(submit, DMA_PQ,
+						      &dest, 1, srcs, 2, len);
+	struct dma_device *dma = chan ? chan->device : NULL;
+	const u8 *amul, *bmul;
+	u8 ax, bx;
+	u8 *a, *b, *c;
+
+	if (dma) {
+		dma_addr_t dma_dest[2];
+		dma_addr_t dma_src[2];
+		struct device *dev = dma->dev;
+		struct dma_async_tx_descriptor *tx;
+		enum dma_ctrl_flags dma_flags = DMA_PREP_PQ_DISABLE_P;
+
+		dma_dest[1] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL);
+		dma_src[0] = dma_map_page(dev, srcs[0], 0, len, DMA_TO_DEVICE);
+		dma_src[1] = dma_map_page(dev, srcs[1], 0, len, DMA_TO_DEVICE);
+		tx = dma->device_prep_dma_pq(chan, dma_dest, dma_src, 2, coef,
+					     len, dma_flags);
+		if (tx) {
+			async_tx_submit(chan, tx, submit);
+			return tx;
+		}
+	}
+
+	/* run the operation synchronously */
+	async_tx_quiesce(&submit->depend_tx);
+	amul = raid6_gfmul[coef[0]];
+	bmul = raid6_gfmul[coef[1]];
+	a = page_address(srcs[0]);
+	b = page_address(srcs[1]);
+	c = page_address(dest);
+
+	while (len--) {
+		ax    = amul[*a++];
+		bx    = bmul[*b++];
+		*c++ = ax ^ bx;
+	}
+
+	return NULL;
+}
+
+/**
+ * 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
+ * @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, struct async_submit_ctl *submit)
+{
+	struct dma_async_tx_descriptor *tx;
+	struct page *p, *q, *dp, *dq;
+	struct page *srcs[2];
+	unsigned char coef[2];
+	enum async_tx_flags flags_orig = submit->flags;
+	dma_async_tx_callback cb_fn_orig = submit->cb_fn;
+	void *cb_param_orig = submit->cb_param;
+
+	/* we need to preserve the contents of 'blocks' for the async
+	 * case, so punt to synchronous if a scribble buffer is not available
+	 */
+	if (!submit->scribble) {
+		void **ptrs = (void **) blocks;
+		int i;
+
+		async_tx_quiesce(&submit->depend_tx);
+		for (i = 0; i < disks; i++)
+			ptrs[i] = page_address(blocks[i]);
+
+		raid6_2data_recov(disks, bytes, faila, failb, ptrs);
+
+		async_tx_sync_epilog(submit);
+
+		return NULL;
+	}
+
+	p = blocks[disks-2];
+	q = blocks[disks-1];
+
+	/* 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];
+	blocks[faila] = (void *)raid6_empty_zero_page;
+	blocks[disks-2] = dp;
+	dq = blocks[failb];
+	blocks[failb] = (void *)raid6_empty_zero_page;
+	blocks[disks-1] = dq;
+
+	submit->flags &= ~ASYNC_TX_ACK;
+	submit->cb_fn = NULL;
+	submit->cb_param = NULL;
+	tx = async_gen_syndrome(blocks, 0, disks, bytes, submit);
+	submit->depend_tx = tx;
+
+	/* Restore pointer table */
+	blocks[faila]   = dp;
+	blocks[failb]   = dq;
+	blocks[disks-2] = p;
+	blocks[disks-1] = q;
+
+	/* compute P + Pxy */
+	srcs[0] = dp;
+	srcs[1] = p;
+	submit->flags |= ASYNC_TX_XOR_DROP_DST;
+	tx = async_xor(dp, srcs, 0, 2, bytes, submit);
+	submit->depend_tx = tx;
+
+	/* compute Q + Qxy */
+	srcs[0] = dq;
+	srcs[1] = q;
+	tx = async_xor(dq, srcs, 0, 2, bytes, submit);
+	submit->depend_tx = tx;
+
+	/* Dx = A*(P+Pxy) + B*(Q+Qxy) */
+	srcs[0] = dp;
+	srcs[1] = dq;
+	coef[0] = raid6_gfexi[failb-faila];
+	coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]];
+	tx = async_sum_product(dq, srcs, coef, bytes, submit);
+	submit->depend_tx = tx;
+
+	/* Dy = P+Pxy+Dx */
+	srcs[0] = dp;
+	srcs[1] = dq;
+	submit->flags = flags_orig | ASYNC_TX_XOR_DROP_DST;
+	submit->cb_fn = cb_fn_orig;
+	submit->cb_param = cb_param_orig;
+	tx = async_xor(dp, srcs, 0, 2, bytes, submit);
+
+	return tx;
+}
+EXPORT_SYMBOL_GPL(async_raid6_2data_recov);
+
+static struct dma_async_tx_descriptor *
+async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
+	   struct async_submit_ctl *submit)
+{
+	struct dma_chan *chan = async_tx_find_channel(submit, DMA_PQ,
+						      &dest, 1, srcs, 2, len);
+	struct dma_device *dma = chan ? chan->device : NULL;
+	const u8 *qmul; /* Q multiplier table */
+	u8 *d, *s;
+
+	if (dma) {
+		dma_addr_t dma_dest[2];
+		dma_addr_t dma_src[1];
+		struct device *dev = dma->dev;
+		struct dma_async_tx_descriptor *tx;
+		enum dma_ctrl_flags dma_flags = DMA_PREP_PQ_DISABLE_P;
+
+		dma_dest[1] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL);
+		dma_src[0] = dma_map_page(dev, src, 0, len, DMA_TO_DEVICE);
+		tx = dma->device_prep_dma_pq(chan, dma_dest, dma_src, 1, &coef,
+					     len, dma_flags);
+		if (tx) {
+			async_tx_submit(chan, tx, submit);
+			return tx;
+		}
+	}
+
+	async_tx_quiesce(&submit->depend_tx);
+	qmul  = raid6_gfmul[coef];
+	d = page_address(dest);
+	s = page_address(src);
+
+	while (len--)
+		*d++ = qmul[*s++];
+
+	return NULL;
+}
+
+/**
+ * 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
+ * @submit: submission/completion modifiers
+ */
+struct dma_async_tx_descriptor *
+async_raid6_datap_recov(int disks, size_t bytes, int faila,
+			struct page **blocks, struct async_submit_ctl *submit)
+{
+	struct dma_async_tx_descriptor *tx;
+	struct page *p, *q, *dq;
+	u8 coef;
+	enum async_tx_flags flags_orig = submit->flags;
+	dma_async_tx_callback cb_fn_orig = submit->cb_fn;
+	void *cb_param_orig = submit->cb_param;
+	struct page *srcs[2];
+
+	/* we need to preserve the contents of 'blocks' for the async
+	 * case, so punt to synchronous if a scribble buffer is not available
+	 */
+	if (!submit->scribble) {
+		void **ptrs = (void **) blocks;
+		int i;
+
+		async_tx_quiesce(&submit->depend_tx);
+		for (i = 0; i < disks; i++)
+			ptrs[i] = page_address(blocks[i]);
+
+		raid6_datap_recov(disks, bytes, faila, ptrs);
+
+		async_tx_sync_epilog(submit);
+
+		return NULL;
+	}
+
+	p = blocks[disks-2];
+	q = blocks[disks-1];
+
+	/* Compute syndrome with zero for the missing data page
+	   Use the dead data page as temporary storage for delta q */
+	dq = blocks[faila];
+	blocks[faila] = (void *)raid6_empty_zero_page;
+	blocks[disks-1] = dq;
+
+	submit->flags &= ~ASYNC_TX_ACK;
+	submit->cb_fn = NULL;
+	submit->cb_param = NULL;
+	tx = async_gen_syndrome(blocks, 0, disks, bytes, submit);
+	submit->depend_tx = tx;
+
+	/* Restore pointer table */
+	blocks[faila]   = dq;
+	blocks[disks-1] = q;
+
+	/* Now, pick the proper data tables */
+	coef = raid6_gfinv[raid6_gfexp[faila]];
+
+	submit->flags |= ASYNC_TX_XOR_DROP_DST;
+	srcs[0] = dq;
+	srcs[1] = q;
+	tx = async_xor(dq, srcs, 0, 2, bytes, submit);
+	submit->depend_tx = tx;
+
+	tx = async_mult(dq, dq, coef, bytes, submit);
+	submit->depend_tx = tx;
+
+	srcs[0] = p;
+	srcs[1] = dq;
+	submit->flags = flags_orig | ASYNC_TX_XOR_DROP_DST;
+	submit->cb_fn = cb_fn_orig;
+	submit->cb_param = cb_param_orig;
+	tx = async_xor(p, srcs, 0, 2, bytes, submit);
+
+	return tx;
+}
+EXPORT_SYMBOL_GPL(async_raid6_datap_recov);
+
+MODULE_AUTHOR("Dan Williams <dan.j.williams@intel.com>");
+MODULE_DESCRIPTION("asynchronous RAID-6 recovery api");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/async_tx.h b/include/linux/async_tx.h
index 6d80022..265e7e2 100644
--- a/include/linux/async_tx.h
+++ b/include/linux/async_tx.h
@@ -171,5 +171,13 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int src_cnt,
 		   size_t len, enum sum_check_flags *pqres,
 		   struct async_submit_ctl *submit);
 
+struct dma_async_tx_descriptor *
+async_raid6_2data_recov(int src_num, size_t bytes, int faila, int failb,
+			struct page **ptrs, struct async_submit_ctl *submit);
+
+struct dma_async_tx_descriptor *
+async_raid6_datap_recov(int src_num, size_t bytes, int faila,
+			struct page **ptrs, struct async_submit_ctl *submit);
+
 void async_tx_quiesce(struct dma_async_tx_descriptor **tx);
 #endif /* _ASYNC_TX_H_ */


  parent reply	other threads:[~2009-05-19  1:00 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-19  0:59 [PATCH v2 00/11] Asynchronous raid6 acceleration (part 1 of 3) Dan Williams
2009-05-19  0:59 ` [PATCH v2 01/11] async_tx: rename zero_sum to val Dan Williams
     [not found]   ` <f12847240905200110x63b22601idbbdf3369984fa9a@mail.gmail.com>
2009-05-29 13:41     ` Sosnowski, Maciej
2009-06-03 18:12       ` Dan Williams
2009-05-19  0:59 ` [PATCH v2 02/11] async_tx: kill ASYNC_TX_DEP_ACK flag Dan Williams
     [not found]   ` <f12847240905250320w74897dabo6576b4b48bd19c0c@mail.gmail.com>
2009-05-29 13:41     ` Sosnowski, Maciej
2009-06-03 18:42       ` Dan Williams
2009-05-19  0:59 ` [PATCH v2 03/11] async_tx: structify submission arguments, add scribble Dan Williams
2009-05-20  8:06   ` Andre Noll
2009-05-20 18:19     ` Dan Williams
     [not found]   ` <f12847240905250321v774c4e8dscd7a466cd2e61168@mail.gmail.com>
2009-05-29 13:41     ` Sosnowski, Maciej
2009-06-03 19:05       ` Dan Williams
2009-05-19  0:59 ` [PATCH v2 04/11] async_xor: permit callers to pass in a 'dma/page scribble' region Dan Williams
2009-05-20  8:08   ` Andre Noll
2009-05-20 18:35     ` Dan Williams
2009-05-20 19:09       ` Andre Noll
2009-05-22  8:29         ` Andre Noll
2009-05-22 17:25           ` Dan Williams
2009-05-25  7:55             ` Andre Noll
     [not found]   ` <f12847240905250320w523fc657w3bca47f23442f46e@mail.gmail.com>
2009-05-29 13:41     ` Sosnowski, Maciej
2009-05-19  0:59 ` [PATCH v2 05/11] md/raid5: add scribble region for buffer lists Dan Williams
2009-05-20  8:09   ` Andre Noll
2009-05-20 19:05     ` Dan Williams
2009-06-04  6:11   ` Neil Brown
2009-06-05 19:19     ` Dan Williams
2009-06-08 17:25       ` Jody McIntyre
2009-05-19  0:59 ` [PATCH v2 06/11] async_tx: add sum check flags Dan Williams
     [not found]   ` <f12847240905200111p54382735v6941b52825cf4d7e@mail.gmail.com>
2009-05-29 13:41     ` Sosnowski, Maciej
2009-05-19  1:00 ` [PATCH v2 07/11] async_tx: kill needless module_{init|exit} Dan Williams
     [not found]   ` <f12847240905250323o21113fb9xbc4c16eea07b215@mail.gmail.com>
2009-05-29 13:42     ` Sosnowski, Maciej
2009-05-19  1:00 ` [PATCH v2 08/11] async_tx: add support for asynchronous GF multiplication Dan Williams
2009-05-22  8:29   ` Andre Noll
2009-06-03 22:11     ` Dan Williams
     [not found]   ` <f12847240905200111q37457b29lb9e30879e251888@mail.gmail.com>
2009-05-29 13:42     ` Sosnowski, Maciej
2009-06-03 22:16       ` Dan Williams
2009-05-19  1:00 ` Dan Williams [this message]
2009-05-22  8:29   ` [PATCH v2 09/11] async_tx: add support for asynchronous RAID6 recovery operations Andre Noll
2009-05-22 18:39     ` Dan Williams
     [not found]   ` <f12847240905250323q2e14efd6q69022a62cc7fd01f@mail.gmail.com>
2009-05-29 13:42     ` Sosnowski, Maciej
2009-05-19  1:00 ` [PATCH v2 10/11] dmatest: add pq support Dan Williams
     [not found]   ` <f12847240905250324t1a55b757hc8cd06d6b9663efe@mail.gmail.com>
2009-05-29 13:42     ` Sosnowski, Maciej
2009-05-19  1:00 ` [PATCH v2 11/11] async_tx: raid6 recovery self test Dan Williams
2009-05-22  8:29   ` Andre Noll
2009-06-03 21:42     ` Dan Williams
     [not found]   ` <f12847240905250324k2b4a0c7as9ac9b084d3707ce5@mail.gmail.com>
2009-05-29 13:42     ` Sosnowski, Maciej

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090519010012.4104.50825.stgit@dwillia2-linux.ch.intel.com \
    --to=dan.j.williams@intel.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-raid@vger.kernel.org \
    --cc=maan@systemlinux.org \
    --cc=neilb@suse.de \
    --cc=yur@emcraft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).