>From 2accd0f9c5d7bfdfa4a1d403be7302aeb8ef4b8a Mon Sep 17 00:00:00 2001
From: Jeff Becker <Jeffrey.C.Becker@nasa.gov>
Date: Fri, 12 Aug 2011 14:27:39 -0700
Subject: [PATCH 1/3] NFSRDMA: bring patches up to date with upstream kernel
 Signed-off-by: Jeff Becker <Jeffrey.C.Becker@nasa.gov>

---
 ...ntial-memory-leak-in-function-rdma_read_x.patch |   42 +++
 ...dma-fix-error-handling-of-rdma_alloc_frmr.patch |   36 ++
 ...RDMA-support-not-yet-compatible-with-RPC6.patch |   39 ++
 ...-not-truncate-iova_start-values-in-frmr-r.patch |   31 ++
 ...x-SQ-size-calculation-when-memreg-is-FRMR.patch |   62 ++++
 ...nge-DMA-mapping-logic-to-avoid-the-page_a.patch |  294 +++++++++++++++
 ...rdma-Cleanup-DMA-unmapping-in-error-paths.patch |  124 +++++++
 ...-sunrpc-xprtrdma-clean-up-workqueue-usage.patch |  135 +++++++
 ...move-resource-leak-in-svc_rdma_send_error.patch |   29 ++
 ...-to-XDR-page-base-interpretation-in-marsh.patch |  195 ++++++++++
 ...Fix-FRMR-registration-invalidate-handling.patch |  175 +++++++++
 ...RDMA-cma-Pass-QP-type-into-rdma_create_id.patch |  379 ++++++++++++++++++++
 ...013-RDMA-Increasing-RPCRDMA_MAX_DATA_SEGS.patch |   31 ++
 .../fixes/nfsrdma_zz_0100_iova_truncate_fix.patch  |   28 --
 .../fixes/nfsrdma_zz_0700_dma_page_map_fix.patch   |  293 ---------------
 .../fixes/nfsrdma_zz_0800_error_path_fix.patch     |  121 -------
 .../fixes/nfsrdma_zz_1400_frmr_sq_depth_fix.patch  |   60 ---
 .../nfsrdma_zz_1500_remove_invalid_bug_on.patch    |   49 ---
 .../fixes/nfsrdma_zz_1700_frmr_inv_fix.patch       |   87 -----
 ...dma_zz_1800_fix_respages_in_read_complete.patch |   29 --
 20 files changed, 1572 insertions(+), 667 deletions(-)
 create mode 100644 kernel_patches/fixes/nfsrdma_0001-sunrpc-potential-memory-leak-in-function-rdma_read_x.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0002-svcrdma-fix-error-handling-of-rdma_alloc_frmr.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0003-svcrdma-RDMA-support-not-yet-compatible-with-RPC6.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0004-xprtrdma-Do-not-truncate-iova_start-values-in-frmr-r.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0005-rpcrdma-Fix-SQ-size-calculation-when-memreg-is-FRMR.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0006-svcrdma-Change-DMA-mapping-logic-to-avoid-the-page_a.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0007-svcrdma-Cleanup-DMA-unmapping-in-error-paths.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0008-sunrpc-xprtrdma-clean-up-workqueue-usage.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0009-SUNRPC-Remove-resource-leak-in-svc_rdma_send_error.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0010-RPCRDMA-Fix-to-XDR-page-base-interpretation-in-marsh.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0011-RPCRDMA-Fix-FRMR-registration-invalidate-handling.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0012-RDMA-cma-Pass-QP-type-into-rdma_create_id.patch
 create mode 100644 kernel_patches/fixes/nfsrdma_0013-RDMA-Increasing-RPCRDMA_MAX_DATA_SEGS.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_0100_iova_truncate_fix.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_0700_dma_page_map_fix.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_0800_error_path_fix.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_1400_frmr_sq_depth_fix.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_1500_remove_invalid_bug_on.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_1700_frmr_inv_fix.patch
 delete mode 100644 kernel_patches/fixes/nfsrdma_zz_1800_fix_respages_in_read_complete.patch

diff --git a/kernel_patches/fixes/nfsrdma_0001-sunrpc-potential-memory-leak-in-function-rdma_read_x.patch b/kernel_patches/fixes/nfsrdma_0001-sunrpc-potential-memory-leak-in-function-rdma_read_x.patch
new file mode 100644
index 0000000..54bf2e6
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0001-sunrpc-potential-memory-leak-in-function-rdma_read_x.patch
@@ -0,0 +1,42 @@
+From 59fb30660be3f3ead54b3850c401d462449caaaa Mon Sep 17 00:00:00 2001
+From: Christian Engelmayer <christian.engelmayer@frequentis.com>
+Date: Sun, 14 Jun 2009 00:05:26 +0200
+Subject: [PATCH] sunrpc: potential memory leak in function rdma_read_xdr
+
+In case the check on ch_count fails the cleanup path is skipped and the
+previously allocated memory 'rpl_map', 'chl_map' is not freed.
+
+Reported by Coverity.
+
+Signed-off-by: Christian Engelmayer <christian.engelmayer@frequentis.com>
+Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
+---
+ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c |    8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+index 42a6f9f..9e88438 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+@@ -397,14 +397,14 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
+ 	if (!ch)
+ 		return 0;
+ 
+-	/* Allocate temporary reply and chunk maps */
+-	rpl_map = svc_rdma_get_req_map();
+-	chl_map = svc_rdma_get_req_map();
+-
+ 	svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
+ 	if (ch_count > RPCSVC_MAXPAGES)
+ 		return -EINVAL;
+ 
++	/* Allocate temporary reply and chunk maps */
++	rpl_map = svc_rdma_get_req_map();
++	chl_map = svc_rdma_get_req_map();
++
+ 	if (!xprt->sc_frmr_pg_list_len)
+ 		sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+ 					    rpl_map, chl_map, ch_count,
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0002-svcrdma-fix-error-handling-of-rdma_alloc_frmr.patch b/kernel_patches/fixes/nfsrdma_0002-svcrdma-fix-error-handling-of-rdma_alloc_frmr.patch
new file mode 100644
index 0000000..28b95ff
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0002-svcrdma-fix-error-handling-of-rdma_alloc_frmr.patch
@@ -0,0 +1,36 @@
+From 846d8e7cc82a6205d5c0a905a4940abd0f565741 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <yjwei@cn.fujitsu.com>
+Date: Thu, 25 Jun 2009 16:35:44 +0800
+Subject: [PATCH] svcrdma: fix error handling of rdma_alloc_frmr()
+
+ib_alloc_fast_reg_mr() and ib_alloc_fast_reg_page_list() returns
+ERR_PTR() and not NULL. Compile tested only.
+
+Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
+Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
+---
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index 5151f9f..0cf5e8c 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -730,12 +730,12 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
+ 		goto err;
+ 
+ 	mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
+-	if (!mr)
++	if (IS_ERR(mr))
+ 		goto err_free_frmr;
+ 
+ 	pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
+ 					 RPCSVC_MAXPAGES);
+-	if (!pl)
++	if (IS_ERR(pl))
+ 		goto err_free_mr;
+ 
+ 	frmr->mr = mr;
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0003-svcrdma-RDMA-support-not-yet-compatible-with-RPC6.patch b/kernel_patches/fixes/nfsrdma_0003-svcrdma-RDMA-support-not-yet-compatible-with-RPC6.patch
new file mode 100644
index 0000000..de59ae8
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0003-svcrdma-RDMA-support-not-yet-compatible-with-RPC6.patch
@@ -0,0 +1,39 @@
+From bade732a2848e640482c1e99629a90e085d574dd Mon Sep 17 00:00:00 2001
+From: Tom Tucker <tom@ogc.us>
+Date: Sat, 3 Apr 2010 08:27:29 -0500
+Subject: [PATCH] svcrdma: RDMA support not yet compatible with RPC6
+
+RPC6 requires that it be possible to create endpoints that listen
+exclusively for IPv4 or IPv6 connection requests. This is not currently
+supported by the RDMA API.
+
+This fixes a server RDMA regression introduced by 37498292a "NFSD:
+Create PF_INET6 listener in write_ports".
+
+Signed-off-by: Tom Tucker<tom@opengridcomputing.com>
+Tested-by: Steve Wise <swise@opengridcomputing.com>
+Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
+---
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |    5 ++++-
+ 1 files changed, 4 insertions(+), 1 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index 3fa5751..4e6bbf9 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -678,7 +678,10 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+ 	int ret;
+ 
+ 	dprintk("svcrdma: Creating RDMA socket\n");
+-
++	if (sa->sa_family != AF_INET) {
++		dprintk("svcrdma: Address family %d is not supported.\n", sa->sa_family);
++		return ERR_PTR(-EAFNOSUPPORT);
++	}
+ 	cma_xprt = rdma_create_xprt(serv, 1);
+ 	if (!cma_xprt)
+ 		return ERR_PTR(-ENOMEM);
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0004-xprtrdma-Do-not-truncate-iova_start-values-in-frmr-r.patch b/kernel_patches/fixes/nfsrdma_0004-xprtrdma-Do-not-truncate-iova_start-values-in-frmr-r.patch
new file mode 100644
index 0000000..5ea6572
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0004-xprtrdma-Do-not-truncate-iova_start-values-in-frmr-r.patch
@@ -0,0 +1,31 @@
+From 7a8b80eb38b248cfdf84048dad12073d5cfba3e6 Mon Sep 17 00:00:00 2001
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Wed, 11 Aug 2010 12:47:08 -0400
+Subject: [PATCH] xprtrdma: Do not truncate iova_start values in frmr registrations.
+
+A bad cast causes the iova_start, which in this case is a 64b DMA
+bus address, to be truncated on 32b systems.  This breaks frmrs on
+32b systems.  No cast is needed.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+---
+ net/sunrpc/xprtrdma/verbs.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
+index 27015c6..3bdbd9f 100644
+--- a/net/sunrpc/xprtrdma/verbs.c
++++ b/net/sunrpc/xprtrdma/verbs.c
+@@ -1490,7 +1490,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
+ 	memset(&frmr_wr, 0, sizeof frmr_wr);
+ 	frmr_wr.opcode = IB_WR_FAST_REG_MR;
+ 	frmr_wr.send_flags = 0;			/* unsignaled */
+-	frmr_wr.wr.fast_reg.iova_start = (unsigned long)seg1->mr_dma;
++	frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
+ 	frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
+ 	frmr_wr.wr.fast_reg.page_list_len = i;
+ 	frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0005-rpcrdma-Fix-SQ-size-calculation-when-memreg-is-FRMR.patch b/kernel_patches/fixes/nfsrdma_0005-rpcrdma-Fix-SQ-size-calculation-when-memreg-is-FRMR.patch
new file mode 100644
index 0000000..6f5005e
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0005-rpcrdma-Fix-SQ-size-calculation-when-memreg-is-FRMR.patch
@@ -0,0 +1,62 @@
+From 15cdc644b268a9a9ce73ce0b153129222c254b7b Mon Sep 17 00:00:00 2001
+From: Tom Tucker <tom@ogc.us>
+Date: Wed, 11 Aug 2010 12:47:24 -0400
+Subject: [PATCH] rpcrdma: Fix SQ size calculation when memreg is FRMR
+
+This patch updates the computation to include the worst case situation
+where three FRMR are required to map a single RPC REQ.
+
+Signed-off-by: Tom Tucker <tom@ogc.us>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+---
+ net/sunrpc/xprtrdma/rpc_rdma.c |    2 ++
+ net/sunrpc/xprtrdma/verbs.c    |   20 ++++++++++++++++----
+ 2 files changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
+index e5e28d1..2ac3f6e 100644
+--- a/net/sunrpc/xprtrdma/rpc_rdma.c
++++ b/net/sunrpc/xprtrdma/rpc_rdma.c
+@@ -249,6 +249,8 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
+ 	req->rl_nchunks = nchunks;
+ 
+ 	BUG_ON(nchunks == 0);
++	BUG_ON((r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR)
++	       && (nchunks > 3));
+ 
+ 	/*
+ 	 * finish off header. If write, marshal discrim and nchunks.
+diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
+index 3bdbd9f..5f4c7b3 100644
+--- a/net/sunrpc/xprtrdma/verbs.c
++++ b/net/sunrpc/xprtrdma/verbs.c
+@@ -650,10 +650,22 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
+ 	ep->rep_attr.cap.max_send_wr = cdata->max_requests;
+ 	switch (ia->ri_memreg_strategy) {
+ 	case RPCRDMA_FRMR:
+-		/* Add room for frmr register and invalidate WRs */
+-		ep->rep_attr.cap.max_send_wr *= 3;
+-		if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr)
+-			return -EINVAL;
++		/* Add room for frmr register and invalidate WRs.
++		 * 1. FRMR reg WR for head
++		 * 2. FRMR invalidate WR for head
++		 * 3. FRMR reg WR for pagelist
++		 * 4. FRMR invalidate WR for pagelist
++		 * 5. FRMR reg WR for tail
++		 * 6. FRMR invalidate WR for tail
++		 * 7. The RDMA_SEND WR
++		 */
++		ep->rep_attr.cap.max_send_wr *= 7;
++		if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) {
++			cdata->max_requests = devattr.max_qp_wr / 7;
++			if (!cdata->max_requests)
++				return -EINVAL;
++			ep->rep_attr.cap.max_send_wr = cdata->max_requests * 7;
++		}
+ 		break;
+ 	case RPCRDMA_MEMWINDOWS_ASYNC:
+ 	case RPCRDMA_MEMWINDOWS:
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0006-svcrdma-Change-DMA-mapping-logic-to-avoid-the-page_a.patch b/kernel_patches/fixes/nfsrdma_0006-svcrdma-Change-DMA-mapping-logic-to-avoid-the-page_a.patch
new file mode 100644
index 0000000..4c8ff34
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0006-svcrdma-Change-DMA-mapping-logic-to-avoid-the-page_a.patch
@@ -0,0 +1,294 @@
+From b432e6b3d9c1b4271c43f02b45136f33a8ed5820 Mon Sep 17 00:00:00 2001
+From: Tom Tucker <tom@ogc.us>
+Date: Tue, 12 Oct 2010 15:33:52 -0500
+Subject: [PATCH] svcrdma: Change DMA mapping logic to avoid the page_address kernel API
+
+There was logic in the send path that assumed that a page containing data
+to send to the client has a KVA. This is not always the case and can result
+in data corruption when page_address returns zero and we end up DMA mapping
+zero.
+
+This patch changes the bus mapping logic to avoid page_address() where
+necessary and converts all calls from ib_dma_map_single to ib_dma_map_page
+in order to keep the map/unmap calls symmetric.
+
+Signed-off-by: Tom Tucker <tom@ogc.us>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+---
+ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c  |   18 ++++---
+ net/sunrpc/xprtrdma/svc_rdma_sendto.c    |   80 +++++++++++++++++++++--------
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |   18 +++---
+ 3 files changed, 78 insertions(+), 38 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+index 0194de8..926bdb4 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+@@ -263,9 +263,9 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
+ 	frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
+ 	for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+ 		frmr->page_list->page_list[page_no] =
+-			ib_dma_map_single(xprt->sc_cm_id->device,
+-					  page_address(rqstp->rq_arg.pages[page_no]),
+-					  PAGE_SIZE, DMA_FROM_DEVICE);
++			ib_dma_map_page(xprt->sc_cm_id->device,
++					rqstp->rq_arg.pages[page_no], 0,
++					PAGE_SIZE, DMA_FROM_DEVICE);
+ 		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ 					 frmr->page_list->page_list[page_no]))
+ 			goto fatal_err;
+@@ -309,17 +309,21 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
+ 			     int count)
+ {
+ 	int i;
++	unsigned long off;
+ 
+ 	ctxt->count = count;
+ 	ctxt->direction = DMA_FROM_DEVICE;
+ 	for (i = 0; i < count; i++) {
+ 		ctxt->sge[i].length = 0; /* in case map fails */
+ 		if (!frmr) {
++			BUG_ON(0 == virt_to_page(vec[i].iov_base));
++			off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
+ 			ctxt->sge[i].addr =
+-				ib_dma_map_single(xprt->sc_cm_id->device,
+-						  vec[i].iov_base,
+-						  vec[i].iov_len,
+-						  DMA_FROM_DEVICE);
++				ib_dma_map_page(xprt->sc_cm_id->device,
++						virt_to_page(vec[i].iov_base),
++						off,
++						vec[i].iov_len,
++						DMA_FROM_DEVICE);
+ 			if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ 						 ctxt->sge[i].addr))
+ 				return -EINVAL;
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+index b15e1eb..d4f5e0e 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+@@ -70,8 +70,8 @@
+  * on extra page for the RPCRMDA header.
+  */
+ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
+-		 struct xdr_buf *xdr,
+-		 struct svc_rdma_req_map *vec)
++			struct xdr_buf *xdr,
++			struct svc_rdma_req_map *vec)
+ {
+ 	int sge_no;
+ 	u32 sge_bytes;
+@@ -96,21 +96,25 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
+ 	vec->count = 2;
+ 	sge_no++;
+ 
+-	/* Build the FRMR */
++	/* Map the XDR head */
+ 	frmr->kva = frva;
+ 	frmr->direction = DMA_TO_DEVICE;
+ 	frmr->access_flags = 0;
+ 	frmr->map_len = PAGE_SIZE;
+ 	frmr->page_list_len = 1;
++	page_off = (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
+ 	frmr->page_list->page_list[page_no] =
+-		ib_dma_map_single(xprt->sc_cm_id->device,
+-				  (void *)xdr->head[0].iov_base,
+-				  PAGE_SIZE, DMA_TO_DEVICE);
++		ib_dma_map_page(xprt->sc_cm_id->device,
++				virt_to_page(xdr->head[0].iov_base),
++				page_off,
++				PAGE_SIZE - page_off,
++				DMA_TO_DEVICE);
+ 	if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ 				 frmr->page_list->page_list[page_no]))
+ 		goto fatal_err;
+ 	atomic_inc(&xprt->sc_dma_used);
+ 
++	/* Map the XDR page list */
+ 	page_off = xdr->page_base;
+ 	page_bytes = xdr->page_len + page_off;
+ 	if (!page_bytes)
+@@ -128,9 +132,9 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
+ 		page_bytes -= sge_bytes;
+ 
+ 		frmr->page_list->page_list[page_no] =
+-			ib_dma_map_single(xprt->sc_cm_id->device,
+-					  page_address(page),
+-					  PAGE_SIZE, DMA_TO_DEVICE);
++			ib_dma_map_page(xprt->sc_cm_id->device,
++					page, page_off,
++					sge_bytes, DMA_TO_DEVICE);
+ 		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ 					 frmr->page_list->page_list[page_no]))
+ 			goto fatal_err;
+@@ -166,8 +170,10 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
+ 		vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+ 
+ 		frmr->page_list->page_list[page_no] =
+-			ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
+-					  DMA_TO_DEVICE);
++		    ib_dma_map_page(xprt->sc_cm_id->device, virt_to_page(va),
++				    page_off,
++				    PAGE_SIZE,
++				    DMA_TO_DEVICE);
+ 		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ 					 frmr->page_list->page_list[page_no]))
+ 			goto fatal_err;
+@@ -245,6 +251,35 @@ static int map_xdr(struct svcxprt_rdma *xprt,
+ 	return 0;
+ }
+ 
++static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt,
++			      struct xdr_buf *xdr,
++			      u32 xdr_off, size_t len, int dir)
++{
++	struct page *page;
++	dma_addr_t dma_addr;
++	if (xdr_off < xdr->head[0].iov_len) {
++		/* This offset is in the head */
++		xdr_off += (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
++		page = virt_to_page(xdr->head[0].iov_base);
++	} else {
++		xdr_off -= xdr->head[0].iov_len;
++		if (xdr_off < xdr->page_len) {
++			/* This offset is in the page list */
++			page = xdr->pages[xdr_off >> PAGE_SHIFT];
++			xdr_off &= ~PAGE_MASK;
++		} else {
++			/* This offset is in the tail */
++			xdr_off -= xdr->page_len;
++			xdr_off += (unsigned long)
++				xdr->tail[0].iov_base & ~PAGE_MASK;
++			page = virt_to_page(xdr->tail[0].iov_base);
++		}
++	}
++	dma_addr = ib_dma_map_page(xprt->sc_cm_id->device, page, xdr_off,
++				   min_t(size_t, PAGE_SIZE, len), dir);
++	return dma_addr;
++}
++
+ /* Assumptions:
+  * - We are using FRMR
+  *     - or -
+@@ -293,10 +328,9 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
+ 		sge[sge_no].length = sge_bytes;
+ 		if (!vec->frmr) {
+ 			sge[sge_no].addr =
+-				ib_dma_map_single(xprt->sc_cm_id->device,
+-						  (void *)
+-						  vec->sge[xdr_sge_no].iov_base + sge_off,
+-						  sge_bytes, DMA_TO_DEVICE);
++				dma_map_xdr(xprt, &rqstp->rq_res, xdr_off,
++					    sge_bytes, DMA_TO_DEVICE);
++			xdr_off += sge_bytes;
+ 			if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ 						 sge[sge_no].addr))
+ 				goto err;
+@@ -494,7 +528,8 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
+  * In all three cases, this function prepares the RPCRDMA header in
+  * sge[0], the 'type' parameter indicates the type to place in the
+  * RPCRDMA header, and the 'byte_count' field indicates how much of
+- * the XDR to include in this RDMA_SEND.
++ * the XDR to include in this RDMA_SEND. NB: The offset of the payload
++ * to send is zero in the XDR.
+  */
+ static int send_reply(struct svcxprt_rdma *rdma,
+ 		      struct svc_rqst *rqstp,
+@@ -536,23 +571,24 @@ static int send_reply(struct svcxprt_rdma *rdma,
+ 	ctxt->sge[0].lkey = rdma->sc_dma_lkey;
+ 	ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
+ 	ctxt->sge[0].addr =
+-		ib_dma_map_single(rdma->sc_cm_id->device, page_address(page),
+-				  ctxt->sge[0].length, DMA_TO_DEVICE);
++	    ib_dma_map_page(rdma->sc_cm_id->device, page, 0,
++			    ctxt->sge[0].length, DMA_TO_DEVICE);
+ 	if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
+ 		goto err;
+ 	atomic_inc(&rdma->sc_dma_used);
+ 
+ 	ctxt->direction = DMA_TO_DEVICE;
+ 
+-	/* Determine how many of our SGE are to be transmitted */
++	/* Map the payload indicated by 'byte_count' */
+ 	for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
++		int xdr_off = 0;
+ 		sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
+ 		byte_count -= sge_bytes;
+ 		if (!vec->frmr) {
+ 			ctxt->sge[sge_no].addr =
+-				ib_dma_map_single(rdma->sc_cm_id->device,
+-						  vec->sge[sge_no].iov_base,
+-						  sge_bytes, DMA_TO_DEVICE);
++				dma_map_xdr(rdma, &rqstp->rq_res, xdr_off,
++					    sge_bytes, DMA_TO_DEVICE);
++			xdr_off += sge_bytes;
+ 			if (ib_dma_mapping_error(rdma->sc_cm_id->device,
+ 						 ctxt->sge[sge_no].addr))
+ 				goto err;
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index 950a206..e87e000 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -121,7 +121,7 @@ void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
+ 		 */
+ 		if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
+ 			atomic_dec(&xprt->sc_dma_used);
+-			ib_dma_unmap_single(xprt->sc_cm_id->device,
++			ib_dma_unmap_page(xprt->sc_cm_id->device,
+ 					    ctxt->sge[i].addr,
+ 					    ctxt->sge[i].length,
+ 					    ctxt->direction);
+@@ -503,8 +503,8 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
+ 		BUG_ON(sge_no >= xprt->sc_max_sge);
+ 		page = svc_rdma_get_page();
+ 		ctxt->pages[sge_no] = page;
+-		pa = ib_dma_map_single(xprt->sc_cm_id->device,
+-				     page_address(page), PAGE_SIZE,
++		pa = ib_dma_map_page(xprt->sc_cm_id->device,
++				     page, 0, PAGE_SIZE,
+ 				     DMA_FROM_DEVICE);
+ 		if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
+ 			goto err_put_ctxt;
+@@ -800,8 +800,8 @@ static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
+ 		if (ib_dma_mapping_error(frmr->mr->device, addr))
+ 			continue;
+ 		atomic_dec(&xprt->sc_dma_used);
+-		ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
+-				    frmr->direction);
++		ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
++				  frmr->direction);
+ 	}
+ }
+ 
+@@ -1276,7 +1276,7 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
+ 				   atomic_read(&xprt->sc_sq_count) <
+ 				   xprt->sc_sq_depth);
+ 			if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
+-				return 0;
++				return -ENOTCONN;
+ 			continue;
+ 		}
+ 		/* Take a transport ref for each WR posted */
+@@ -1322,8 +1322,8 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ 	length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
+ 
+ 	/* Prepare SGE for local address */
+-	sge.addr = ib_dma_map_single(xprt->sc_cm_id->device,
+-				   page_address(p), PAGE_SIZE, DMA_FROM_DEVICE);
++	sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
++				   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ 	if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
+ 		put_page(p);
+ 		return;
+@@ -1350,7 +1350,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ 	if (ret) {
+ 		dprintk("svcrdma: Error %d posting send for protocol error\n",
+ 			ret);
+-		ib_dma_unmap_single(xprt->sc_cm_id->device,
++		ib_dma_unmap_page(xprt->sc_cm_id->device,
+ 				  sge.addr, PAGE_SIZE,
+ 				  DMA_FROM_DEVICE);
+ 		svc_rdma_put_context(ctxt, 1);
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0007-svcrdma-Cleanup-DMA-unmapping-in-error-paths.patch b/kernel_patches/fixes/nfsrdma_0007-svcrdma-Cleanup-DMA-unmapping-in-error-paths.patch
new file mode 100644
index 0000000..c35729c
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0007-svcrdma-Cleanup-DMA-unmapping-in-error-paths.patch
@@ -0,0 +1,124 @@
+From 4a84386fc27fdc7d2ea69fdbc641008e8f943159 Mon Sep 17 00:00:00 2001
+From: Tom Tucker <tom@ogc.us>
+Date: Tue, 12 Oct 2010 15:33:57 -0500
+Subject: [PATCH] svcrdma: Cleanup DMA unmapping in error paths.
+
+There are several error paths in the code that do not unmap DMA. This
+patch adds calls to svc_rdma_unmap_dma to free these DMA contexts.
+
+Signed-off-by: Tom Tucker <tom@opengridcomputing.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+---
+ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c  |    1 +
+ net/sunrpc/xprtrdma/svc_rdma_sendto.c    |    2 ++
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |   29 ++++++++++++++---------------
+ 3 files changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+index 926bdb4..df67211 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+@@ -495,6 +495,7 @@ next_sge:
+ 			printk(KERN_ERR "svcrdma: Error %d posting RDMA_READ\n",
+ 			       err);
+ 			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
++			svc_rdma_unmap_dma(ctxt);
+ 			svc_rdma_put_context(ctxt, 0);
+ 			goto out;
+ 		}
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+index d4f5e0e..249a835 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+@@ -367,6 +367,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
+ 		goto err;
+ 	return 0;
+  err:
++	svc_rdma_unmap_dma(ctxt);
++	svc_rdma_put_frmr(xprt, vec->frmr);
+ 	svc_rdma_put_context(ctxt, 0);
+ 	/* Fatal error, close transport */
+ 	return -EIO;
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index e87e000..22f65cc 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -512,9 +512,9 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
+ 		ctxt->sge[sge_no].addr = pa;
+ 		ctxt->sge[sge_no].length = PAGE_SIZE;
+ 		ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
++		ctxt->count = sge_no + 1;
+ 		buflen += PAGE_SIZE;
+ 	}
+-	ctxt->count = sge_no;
+ 	recv_wr.next = NULL;
+ 	recv_wr.sg_list = &ctxt->sge[0];
+ 	recv_wr.num_sge = ctxt->count;
+@@ -530,6 +530,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
+ 	return ret;
+ 
+  err_put_ctxt:
++	svc_rdma_unmap_dma(ctxt);
+ 	svc_rdma_put_context(ctxt, 1);
+ 	return -ENOMEM;
+ }
+@@ -1308,7 +1309,6 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ 			 enum rpcrdma_errcode err)
+ {
+ 	struct ib_send_wr err_wr;
+-	struct ib_sge sge;
+ 	struct page *p;
+ 	struct svc_rdma_op_ctxt *ctxt;
+ 	u32 *va;
+@@ -1321,26 +1321,27 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ 	/* XDR encode error */
+ 	length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
+ 
++	ctxt = svc_rdma_get_context(xprt);
++	ctxt->direction = DMA_FROM_DEVICE;
++	ctxt->count = 1;
++	ctxt->pages[0] = p;
++
+ 	/* Prepare SGE for local address */
+-	sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
+-				   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+-	if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
++	ctxt->sge[0].addr = ib_dma_map_page(xprt->sc_cm_id->device,
++					    p, 0, length, DMA_FROM_DEVICE);
++	if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
+ 		put_page(p);
+ 		return;
+ 	}
+ 	atomic_inc(&xprt->sc_dma_used);
+-	sge.lkey = xprt->sc_dma_lkey;
+-	sge.length = length;
+-
+-	ctxt = svc_rdma_get_context(xprt);
+-	ctxt->count = 1;
+-	ctxt->pages[0] = p;
++	ctxt->sge[0].lkey = xprt->sc_dma_lkey;
++	ctxt->sge[0].length = length;
+ 
+ 	/* Prepare SEND WR */
+ 	memset(&err_wr, 0, sizeof err_wr);
+ 	ctxt->wr_op = IB_WR_SEND;
+ 	err_wr.wr_id = (unsigned long)ctxt;
+-	err_wr.sg_list = &sge;
++	err_wr.sg_list = ctxt->sge;
+ 	err_wr.num_sge = 1;
+ 	err_wr.opcode = IB_WR_SEND;
+ 	err_wr.send_flags = IB_SEND_SIGNALED;
+@@ -1350,9 +1351,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ 	if (ret) {
+ 		dprintk("svcrdma: Error %d posting send for protocol error\n",
+ 			ret);
+-		ib_dma_unmap_page(xprt->sc_cm_id->device,
+-				  sge.addr, PAGE_SIZE,
+-				  DMA_FROM_DEVICE);
++		svc_rdma_unmap_dma(ctxt);
+ 		svc_rdma_put_context(ctxt, 1);
+ 	}
+ }
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0008-sunrpc-xprtrdma-clean-up-workqueue-usage.patch b/kernel_patches/fixes/nfsrdma_0008-sunrpc-xprtrdma-clean-up-workqueue-usage.patch
new file mode 100644
index 0000000..40eac25
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0008-sunrpc-xprtrdma-clean-up-workqueue-usage.patch
@@ -0,0 +1,135 @@
+From a25e758c5fa1137e1bbc440194e55f7c59177145 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Fri, 15 Oct 2010 17:49:27 +0200
+Subject: [PATCH] sunrpc/xprtrdma: clean up workqueue usage
+
+* Create and use svc_rdma_wq instead of using the system workqueue and
+  flush_scheduled_work().  This workqueue is necessary to serve as
+  flushing domain for rdma->sc_work which is used to destroy itself
+  and thus can't be flushed explicitly.
+
+* Replace cancel_delayed_work() + flush_scheduled_work() with
+  cancel_delayed_work_sync().
+
+* Implement synchronous connect in xprt_rdma_connect() using
+  flush_delayed_work() on the rdma_connect work instead of using
+  flush_scheduled_work().
+
+This is to prepare for the deprecation and removal of
+flush_scheduled_work().
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+---
+ net/sunrpc/xprtrdma/svc_rdma.c           |   11 ++++++++++-
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |    6 +++++-
+ net/sunrpc/xprtrdma/transport.c          |    5 ++---
+ 3 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
+index d718b8f..09af4fa 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma.c
++++ b/net/sunrpc/xprtrdma/svc_rdma.c
+@@ -43,6 +43,7 @@
+ #include <linux/slab.h>
+ #include <linux/fs.h>
+ #include <linux/sysctl.h>
++#include <linux/workqueue.h>
+ #include <linux/sunrpc/clnt.h>
+ #include <linux/sunrpc/sched.h>
+ #include <linux/sunrpc/svc_rdma.h>
+@@ -74,6 +75,8 @@ atomic_t rdma_stat_sq_prod;
+ struct kmem_cache *svc_rdma_map_cachep;
+ struct kmem_cache *svc_rdma_ctxt_cachep;
+ 
++struct workqueue_struct *svc_rdma_wq;
++
+ /*
+  * This function implements reading and resetting an atomic_t stat
+  * variable through read/write to a proc file. Any write to the file
+@@ -231,7 +234,7 @@ static ctl_table svcrdma_root_table[] = {
+ void svc_rdma_cleanup(void)
+ {
+ 	dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
+-	flush_scheduled_work();
++	destroy_workqueue(svc_rdma_wq);
+ 	if (svcrdma_table_header) {
+ 		unregister_sysctl_table(svcrdma_table_header);
+ 		svcrdma_table_header = NULL;
+@@ -249,6 +252,11 @@ int svc_rdma_init(void)
+ 	dprintk("\tsq_depth         : %d\n",
+ 		svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT);
+ 	dprintk("\tmax_inline       : %d\n", svcrdma_max_req_size);
++
++	svc_rdma_wq = alloc_workqueue("svc_rdma", 0, 0);
++	if (!svc_rdma_wq)
++		return -ENOMEM;
++
+ 	if (!svcrdma_table_header)
+ 		svcrdma_table_header =
+ 			register_sysctl_table(svcrdma_root_table);
+@@ -283,6 +291,7 @@ int svc_rdma_init(void)
+ 	kmem_cache_destroy(svc_rdma_map_cachep);
+  err0:
+ 	unregister_sysctl_table(svcrdma_table_header);
++	destroy_workqueue(svc_rdma_wq);
+ 	return -ENOMEM;
+ }
+ MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index 22f65cc..9df1ead 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -45,6 +45,7 @@
+ #include <linux/sched.h>
+ #include <linux/slab.h>
+ #include <linux/spinlock.h>
++#include <linux/workqueue.h>
+ #include <rdma/ib_verbs.h>
+ #include <rdma/rdma_cm.h>
+ #include <linux/sunrpc/svc_rdma.h>
+@@ -90,6 +91,9 @@ struct svc_xprt_class svc_rdma_class = {
+ /* WR context cache. Created in svc_rdma.c  */
+ extern struct kmem_cache *svc_rdma_ctxt_cachep;
+ 
++/* Workqueue created in svc_rdma.c */
++extern struct workqueue_struct *svc_rdma_wq;
++
+ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
+ {
+ 	struct svc_rdma_op_ctxt *ctxt;
+@@ -1187,7 +1191,7 @@ static void svc_rdma_free(struct svc_xprt *xprt)
+ 	struct svcxprt_rdma *rdma =
+ 		container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ 	INIT_WORK(&rdma->sc_work, __svc_rdma_free);
+-	schedule_work(&rdma->sc_work);
++	queue_work(svc_rdma_wq, &rdma->sc_work);
+ }
+ 
+ static int svc_rdma_has_wspace(struct svc_xprt *xprt)
+diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
+index 2da32b4..0867070 100644
+--- a/net/sunrpc/xprtrdma/transport.c
++++ b/net/sunrpc/xprtrdma/transport.c
+@@ -237,8 +237,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
+ 
+ 	dprintk("RPC:       %s: called\n", __func__);
+ 
+-	cancel_delayed_work(&r_xprt->rdma_connect);
+-	flush_scheduled_work();
++	cancel_delayed_work_sync(&r_xprt->rdma_connect);
+ 
+ 	xprt_clear_connected(xprt);
+ 
+@@ -448,7 +447,7 @@ xprt_rdma_connect(struct rpc_task *task)
+ 	} else {
+ 		schedule_delayed_work(&r_xprt->rdma_connect, 0);
+ 		if (!RPC_IS_ASYNC(task))
+-			flush_scheduled_work();
++			flush_delayed_work(&r_xprt->rdma_connect);
+ 	}
+ }
+ 
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0009-SUNRPC-Remove-resource-leak-in-svc_rdma_send_error.patch b/kernel_patches/fixes/nfsrdma_0009-SUNRPC-Remove-resource-leak-in-svc_rdma_send_error.patch
new file mode 100644
index 0000000..31c3e9b
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0009-SUNRPC-Remove-resource-leak-in-svc_rdma_send_error.patch
@@ -0,0 +1,29 @@
+From a5e502681007779d4762fb3ef7e80a3ecd1cfe6b Mon Sep 17 00:00:00 2001
+From: Jesper Juhl <jj@chaosbits.net>
+Date: Sat, 22 Jan 2011 21:40:20 +0000
+Subject: [PATCH] SUNRPC: Remove resource leak in svc_rdma_send_error()
+
+We leak the memory allocated to 'ctxt' when we return after
+'ib_dma_mapping_error()' returns !=0.
+
+Signed-off-by: Jesper Juhl <jj@chaosbits.net>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+---
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index 9df1ead..1a10dcd 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -1335,6 +1335,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ 					    p, 0, length, DMA_FROM_DEVICE);
+ 	if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
+ 		put_page(p);
++		svc_rdma_put_context(ctxt, 1);
+ 		return;
+ 	}
+ 	atomic_inc(&xprt->sc_dma_used);
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0010-RPCRDMA-Fix-to-XDR-page-base-interpretation-in-marsh.patch b/kernel_patches/fixes/nfsrdma_0010-RPCRDMA-Fix-to-XDR-page-base-interpretation-in-marsh.patch
new file mode 100644
index 0000000..f12fe5a
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0010-RPCRDMA-Fix-to-XDR-page-base-interpretation-in-marsh.patch
@@ -0,0 +1,195 @@
+From bd7ea31b9e8a342be76e0fe8d638343886c2d8c5 Mon Sep 17 00:00:00 2001
+From: Tom Tucker <tom@ogc.us>
+Date: Wed, 9 Feb 2011 19:45:28 +0000
+Subject: [PATCH] RPCRDMA: Fix to XDR page base interpretation in marshalling logic.
+
+The RPCRDMA marshalling logic assumed that xdr->page_base was an
+offset into the first page of xdr->page_list. It is in fact an
+offset into the xdr->page_list itself, that is, it selects the
+first page in the page_list and the offset into that page.
+
+The symptom depended in part on the rpc_memreg_strategy, if it was
+FRMR, or some other one-shot mapping mode, the connection would get
+torn down on a base and bounds error. When the badly marshalled RPC
+was retransmitted it would reconnect, get the error, and tear down the
+connection again in a loop forever. This resulted in a hung-mount. For
+the other modes, it would result in silent data corruption. This bug is
+most easily reproduced by writing more data than the filesystem
+has space for.
+
+This fix corrects the page_base assumption and otherwise simplifies
+the iov mapping logic.
+
+Signed-off-by: Tom Tucker <tom@ogc.us>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+---
+ net/sunrpc/xprtrdma/rpc_rdma.c |   86 +++++++++++++++++++--------------------
+ 1 files changed, 42 insertions(+), 44 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
+index 2ac3f6e..554d081 100644
+--- a/net/sunrpc/xprtrdma/rpc_rdma.c
++++ b/net/sunrpc/xprtrdma/rpc_rdma.c
+@@ -87,6 +87,8 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
+ 	enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs)
+ {
+ 	int len, n = 0, p;
++	int page_base;
++	struct page **ppages;
+ 
+ 	if (pos == 0 && xdrbuf->head[0].iov_len) {
+ 		seg[n].mr_page = NULL;
+@@ -95,34 +97,32 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
+ 		++n;
+ 	}
+ 
+-	if (xdrbuf->page_len && (xdrbuf->pages[0] != NULL)) {
+-		if (n == nsegs)
+-			return 0;
+-		seg[n].mr_page = xdrbuf->pages[0];
+-		seg[n].mr_offset = (void *)(unsigned long) xdrbuf->page_base;
+-		seg[n].mr_len = min_t(u32,
+-			PAGE_SIZE - xdrbuf->page_base, xdrbuf->page_len);
+-		len = xdrbuf->page_len - seg[n].mr_len;
++	len = xdrbuf->page_len;
++	ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT);
++	page_base = xdrbuf->page_base & ~PAGE_MASK;
++	p = 0;
++	while (len && n < nsegs) {
++		seg[n].mr_page = ppages[p];
++		seg[n].mr_offset = (void *)(unsigned long) page_base;
++		seg[n].mr_len = min_t(u32, PAGE_SIZE - page_base, len);
++		BUG_ON(seg[n].mr_len > PAGE_SIZE);
++		len -= seg[n].mr_len;
+ 		++n;
+-		p = 1;
+-		while (len > 0) {
+-			if (n == nsegs)
+-				return 0;
+-			seg[n].mr_page = xdrbuf->pages[p];
+-			seg[n].mr_offset = NULL;
+-			seg[n].mr_len = min_t(u32, PAGE_SIZE, len);
+-			len -= seg[n].mr_len;
+-			++n;
+-			++p;
+-		}
++		++p;
++		page_base = 0;	/* page offset only applies to first page */
+ 	}
+ 
++	/* Message overflows the seg array */
++	if (len && n == nsegs)
++		return 0;
++
+ 	if (xdrbuf->tail[0].iov_len) {
+ 		/* the rpcrdma protocol allows us to omit any trailing
+ 		 * xdr pad bytes, saving the server an RDMA operation. */
+ 		if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize)
+ 			return n;
+ 		if (n == nsegs)
++			/* Tail remains, but we're out of segments */
+ 			return 0;
+ 		seg[n].mr_page = NULL;
+ 		seg[n].mr_offset = xdrbuf->tail[0].iov_base;
+@@ -296,6 +296,8 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
+ 	int copy_len;
+ 	unsigned char *srcp, *destp;
+ 	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
++	int page_base;
++	struct page **ppages;
+ 
+ 	destp = rqst->rq_svec[0].iov_base;
+ 	curlen = rqst->rq_svec[0].iov_len;
+@@ -324,28 +326,25 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
+ 			__func__, destp + copy_len, curlen);
+ 		rqst->rq_svec[0].iov_len += curlen;
+ 	}
+-
+ 	r_xprt->rx_stats.pullup_copy_count += copy_len;
+-	npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
++
++	page_base = rqst->rq_snd_buf.page_base;
++	ppages = rqst->rq_snd_buf.pages + (page_base >> PAGE_SHIFT);
++	page_base &= ~PAGE_MASK;
++	npages = PAGE_ALIGN(page_base+copy_len) >> PAGE_SHIFT;
+ 	for (i = 0; copy_len && i < npages; i++) {
+-		if (i == 0)
+-			curlen = PAGE_SIZE - rqst->rq_snd_buf.page_base;
+-		else
+-			curlen = PAGE_SIZE;
++		curlen = PAGE_SIZE - page_base;
+ 		if (curlen > copy_len)
+ 			curlen = copy_len;
+ 		dprintk("RPC:       %s: page %d destp 0x%p len %d curlen %d\n",
+ 			__func__, i, destp, copy_len, curlen);
+-		srcp = kmap_atomic(rqst->rq_snd_buf.pages[i],
+-					KM_SKB_SUNRPC_DATA);
+-		if (i == 0)
+-			memcpy(destp, srcp+rqst->rq_snd_buf.page_base, curlen);
+-		else
+-			memcpy(destp, srcp, curlen);
++		srcp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA);
++		memcpy(destp, srcp+page_base, curlen);
+ 		kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA);
+ 		rqst->rq_svec[0].iov_len += curlen;
+ 		destp += curlen;
+ 		copy_len -= curlen;
++		page_base = 0;
+ 	}
+ 	/* header now contains entire send message */
+ 	return pad;
+@@ -606,6 +605,8 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
+ {
+ 	int i, npages, curlen, olen;
+ 	char *destp;
++	struct page **ppages;
++	int page_base;
+ 
+ 	curlen = rqst->rq_rcv_buf.head[0].iov_len;
+ 	if (curlen > copy_len) {	/* write chunk header fixup */
+@@ -624,32 +625,29 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
+ 	olen = copy_len;
+ 	i = 0;
+ 	rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen;
++	page_base = rqst->rq_rcv_buf.page_base;
++	ppages = rqst->rq_rcv_buf.pages + (page_base >> PAGE_SHIFT);
++	page_base &= ~PAGE_MASK;
++
+ 	if (copy_len && rqst->rq_rcv_buf.page_len) {
+-		npages = PAGE_ALIGN(rqst->rq_rcv_buf.page_base +
++		npages = PAGE_ALIGN(page_base +
+ 			rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT;
+ 		for (; i < npages; i++) {
+-			if (i == 0)
+-				curlen = PAGE_SIZE - rqst->rq_rcv_buf.page_base;
+-			else
+-				curlen = PAGE_SIZE;
++			curlen = PAGE_SIZE - page_base;
+ 			if (curlen > copy_len)
+ 				curlen = copy_len;
+ 			dprintk("RPC:       %s: page %d"
+ 				" srcp 0x%p len %d curlen %d\n",
+ 				__func__, i, srcp, copy_len, curlen);
+-			destp = kmap_atomic(rqst->rq_rcv_buf.pages[i],
+-						KM_SKB_SUNRPC_DATA);
+-			if (i == 0)
+-				memcpy(destp + rqst->rq_rcv_buf.page_base,
+-						srcp, curlen);
+-			else
+-				memcpy(destp, srcp, curlen);
+-			flush_dcache_page(rqst->rq_rcv_buf.pages[i]);
++			destp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA);
++			memcpy(destp + page_base, srcp, curlen);
++			flush_dcache_page(ppages[i]);
+ 			kunmap_atomic(destp, KM_SKB_SUNRPC_DATA);
+ 			srcp += curlen;
+ 			copy_len -= curlen;
+ 			if (copy_len == 0)
+ 				break;
++			page_base = 0;
+ 		}
+ 		rqst->rq_rcv_buf.page_len = olen - copy_len;
+ 	} else
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0011-RPCRDMA-Fix-FRMR-registration-invalidate-handling.patch b/kernel_patches/fixes/nfsrdma_0011-RPCRDMA-Fix-FRMR-registration-invalidate-handling.patch
new file mode 100644
index 0000000..666ebef
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0011-RPCRDMA-Fix-FRMR-registration-invalidate-handling.patch
@@ -0,0 +1,175 @@
+From 5c635e09cec0feeeb310968e51dad01040244851 Mon Sep 17 00:00:00 2001
+From: Tom Tucker <tom@ogc.us>
+Date: Wed, 9 Feb 2011 19:45:34 +0000
+Subject: [PATCH] RPCRDMA: Fix FRMR registration/invalidate handling.
+
+When the rpc_memreg_strategy is 5, FRMR are used to map RPC data.
+This mode uses an FRMR to map the RPC data, then invalidates
+(i.e. unregisers) the data in xprt_rdma_free. These FRMR are used
+across connections on the same mount, i.e. if the connection goes
+away on an idle timeout and reconnects later, the FRMR are not
+destroyed and recreated.
+
+This creates a problem for transport errors because the WR that
+invalidate an FRMR may be flushed (i.e. fail) leaving the
+FRMR valid. When the FRMR is later used to map an RPC it will fail,
+tearing down the transport and starting over. Over time, more and
+more of the FRMR pool end up in the wrong state resulting in
+seemingly random disconnects.
+
+This fix keeps track of the FRMR state explicitly by setting it's
+state based on the successful completion of a reg/inv WR. If the FRMR
+is ever used and found to be in the wrong state, an invalidate WR
+is prepended, re-syncing the FRMR state and avoiding the connection loss.
+
+Signed-off-by: Tom Tucker <tom@ogc.us>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+---
+ net/sunrpc/xprtrdma/verbs.c     |   52 +++++++++++++++++++++++++++++++++------
+ net/sunrpc/xprtrdma/xprt_rdma.h |    1 +
+ 2 files changed, 45 insertions(+), 8 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
+index 5f4c7b3..570f08d 100644
+--- a/net/sunrpc/xprtrdma/verbs.c
++++ b/net/sunrpc/xprtrdma/verbs.c
+@@ -144,6 +144,7 @@ rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
+ static inline
+ void rpcrdma_event_process(struct ib_wc *wc)
+ {
++	struct rpcrdma_mw *frmr;
+ 	struct rpcrdma_rep *rep =
+ 			(struct rpcrdma_rep *)(unsigned long) wc->wr_id;
+ 
+@@ -154,15 +155,23 @@ void rpcrdma_event_process(struct ib_wc *wc)
+ 		return;
+ 
+ 	if (IB_WC_SUCCESS != wc->status) {
+-		dprintk("RPC:       %s: %s WC status %X, connection lost\n",
+-			__func__, (wc->opcode & IB_WC_RECV) ? "recv" : "send",
+-			 wc->status);
++		dprintk("RPC:       %s: WC opcode %d status %X, connection lost\n",
++			__func__, wc->opcode, wc->status);
+ 		rep->rr_len = ~0U;
+-		rpcrdma_schedule_tasklet(rep);
++		if (wc->opcode != IB_WC_FAST_REG_MR && wc->opcode != IB_WC_LOCAL_INV)
++			rpcrdma_schedule_tasklet(rep);
+ 		return;
+ 	}
+ 
+ 	switch (wc->opcode) {
++	case IB_WC_FAST_REG_MR:
++		frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
++		frmr->r.frmr.state = FRMR_IS_VALID;
++		break;
++	case IB_WC_LOCAL_INV:
++		frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
++		frmr->r.frmr.state = FRMR_IS_INVALID;
++		break;
+ 	case IB_WC_RECV:
+ 		rep->rr_len = wc->byte_len;
+ 		ib_dma_sync_single_for_cpu(
+@@ -1450,6 +1459,11 @@ rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing)
+ 		seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
+ 				seg->mr_offset,
+ 				seg->mr_dmalen, seg->mr_dir);
++	if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) {
++		dprintk("RPC:       %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n",
++			__func__,
++			seg->mr_dma, seg->mr_offset, seg->mr_dmalen);
++	}
+ }
+ 
+ static void
+@@ -1469,7 +1483,8 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
+ 			struct rpcrdma_xprt *r_xprt)
+ {
+ 	struct rpcrdma_mr_seg *seg1 = seg;
+-	struct ib_send_wr frmr_wr, *bad_wr;
++	struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr;
++
+ 	u8 key;
+ 	int len, pageoff;
+ 	int i, rc;
+@@ -1484,6 +1499,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
+ 		rpcrdma_map_one(ia, seg, writing);
+ 		seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma;
+ 		len += seg->mr_len;
++		BUG_ON(seg->mr_len > PAGE_SIZE);
+ 		++seg;
+ 		++i;
+ 		/* Check for holes */
+@@ -1494,26 +1510,45 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
+ 	dprintk("RPC:       %s: Using frmr %p to map %d segments\n",
+ 		__func__, seg1->mr_chunk.rl_mw, i);
+ 
++	if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) {
++		dprintk("RPC:       %s: frmr %x left valid, posting invalidate.\n",
++			__func__,
++			seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey);
++		/* Invalidate before using. */
++		memset(&invalidate_wr, 0, sizeof invalidate_wr);
++		invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
++		invalidate_wr.next = &frmr_wr;
++		invalidate_wr.opcode = IB_WR_LOCAL_INV;
++		invalidate_wr.send_flags = IB_SEND_SIGNALED;
++		invalidate_wr.ex.invalidate_rkey =
++			seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
++		DECR_CQCOUNT(&r_xprt->rx_ep);
++		post_wr = &invalidate_wr;
++	} else
++		post_wr = &frmr_wr;
++
+ 	/* Bump the key */
+ 	key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF);
+ 	ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key);
+ 
+ 	/* Prepare FRMR WR */
+ 	memset(&frmr_wr, 0, sizeof frmr_wr);
++	frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
+ 	frmr_wr.opcode = IB_WR_FAST_REG_MR;
+-	frmr_wr.send_flags = 0;			/* unsignaled */
++	frmr_wr.send_flags = IB_SEND_SIGNALED;
+ 	frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
+ 	frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
+ 	frmr_wr.wr.fast_reg.page_list_len = i;
+ 	frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
+ 	frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT;
++	BUG_ON(frmr_wr.wr.fast_reg.length < len);
+ 	frmr_wr.wr.fast_reg.access_flags = (writing ?
+ 				IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
+ 				IB_ACCESS_REMOTE_READ);
+ 	frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
+ 	DECR_CQCOUNT(&r_xprt->rx_ep);
+ 
+-	rc = ib_post_send(ia->ri_id->qp, &frmr_wr, &bad_wr);
++	rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr);
+ 
+ 	if (rc) {
+ 		dprintk("RPC:       %s: failed ib_post_send for register,"
+@@ -1542,8 +1577,9 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg,
+ 		rpcrdma_unmap_one(ia, seg++);
+ 
+ 	memset(&invalidate_wr, 0, sizeof invalidate_wr);
++	invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
+ 	invalidate_wr.opcode = IB_WR_LOCAL_INV;
+-	invalidate_wr.send_flags = 0;			/* unsignaled */
++	invalidate_wr.send_flags = IB_SEND_SIGNALED;
+ 	invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
+ 	DECR_CQCOUNT(&r_xprt->rx_ep);
+ 
+diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
+index c7a7eba..cae761a 100644
+--- a/net/sunrpc/xprtrdma/xprt_rdma.h
++++ b/net/sunrpc/xprtrdma/xprt_rdma.h
+@@ -164,6 +164,7 @@ struct rpcrdma_mr_seg {		/* chunk descriptors */
+ 				struct {
+ 					struct ib_fast_reg_page_list *fr_pgl;
+ 					struct ib_mr *fr_mr;
++					enum { FRMR_IS_INVALID, FRMR_IS_VALID  } state;
+ 				} frmr;
+ 			} r;
+ 			struct list_head mw_list;
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0012-RDMA-cma-Pass-QP-type-into-rdma_create_id.patch b/kernel_patches/fixes/nfsrdma_0012-RDMA-cma-Pass-QP-type-into-rdma_create_id.patch
new file mode 100644
index 0000000..8142c5c
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0012-RDMA-cma-Pass-QP-type-into-rdma_create_id.patch
@@ -0,0 +1,379 @@
+From b26f9b9949013fec31b23c426fc463164ae08891 Mon Sep 17 00:00:00 2001
+From: Sean Hefty <sean.hefty@intel.com>
+Date: Thu, 1 Apr 2010 17:08:41 +0000
+Subject: [PATCH] RDMA/cma: Pass QP type into rdma_create_id()
+
+The RDMA CM currently infers the QP type from the port space selected
+by the user.  In the future (eg with RDMA_PS_IB or XRC), there may not
+be a 1-1 correspondence between port space and QP type.  For netlink
+export of RDMA CM state, we want to export the QP type to userspace,
+so it is cleaner to explicitly associate a QP type to an ID.
+
+Modify rdma_create_id() to allow the user to specify the QP type, and
+use it to make our selections of datagram versus connected mode.
+
+Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+---
+ drivers/infiniband/core/cma.c            |   35 +++++++++++++----------------
+ drivers/infiniband/core/ucma.c           |   27 +++++++++++++++++++---
+ drivers/infiniband/ulp/iser/iser_verbs.c |    2 +-
+ include/rdma/rdma_cm.h                   |    5 +++-
+ net/9p/trans_rdma.c                      |    3 +-
+ net/rds/ib.c                             |    2 +-
+ net/rds/ib_cm.c                          |    2 +-
+ net/rds/iw.c                             |    2 +-
+ net/rds/iw_cm.c                          |    2 +-
+ net/rds/rdma_transport.c                 |    3 +-
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |    3 +-
+ net/sunrpc/xprtrdma/verbs.c              |    2 +-
+ 12 files changed, 55 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index 451d39e..44be1c9e 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -265,11 +265,6 @@ static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
+ 	hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
+ }
+ 
+-static inline int cma_is_ud_ps(enum rdma_port_space ps)
+-{
+-	return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
+-}
+-
+ static void cma_attach_to_dev(struct rdma_id_private *id_priv,
+ 			      struct cma_device *cma_dev)
+ {
+@@ -415,7 +410,8 @@ static int cma_has_cm_dev(struct rdma_id_private *id_priv)
+ }
+ 
+ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+-				  void *context, enum rdma_port_space ps)
++				  void *context, enum rdma_port_space ps,
++				  enum ib_qp_type qp_type)
+ {
+ 	struct rdma_id_private *id_priv;
+ 
+@@ -427,6 +423,7 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+ 	id_priv->id.context = context;
+ 	id_priv->id.event_handler = event_handler;
+ 	id_priv->id.ps = ps;
++	id_priv->id.qp_type = qp_type;
+ 	spin_lock_init(&id_priv->lock);
+ 	mutex_init(&id_priv->qp_mutex);
+ 	init_completion(&id_priv->comp);
+@@ -494,7 +491,7 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
+ 	if (IS_ERR(qp))
+ 		return PTR_ERR(qp);
+ 
+-	if (cma_is_ud_ps(id_priv->id.ps))
++	if (id->qp_type == IB_QPT_UD)
+ 		ret = cma_init_ud_qp(id_priv, qp);
+ 	else
+ 		ret = cma_init_conn_qp(id_priv, qp);
+@@ -622,7 +619,7 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
+ 	qp_attr->port_num = id_priv->id.port_num;
+ 	*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
+ 
+-	if (cma_is_ud_ps(id_priv->id.ps)) {
++	if (id_priv->id.qp_type == IB_QPT_UD) {
+ 		ret = cma_set_qkey(id_priv);
+ 		if (ret)
+ 			return ret;
+@@ -645,7 +642,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
+ 	id_priv = container_of(id, struct rdma_id_private, id);
+ 	switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
+ 	case RDMA_TRANSPORT_IB:
+-		if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps))
++		if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD))
+ 			ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask);
+ 		else
+ 			ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
+@@ -1088,7 +1085,7 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
+ 		goto err;
+ 
+ 	id = rdma_create_id(listen_id->event_handler, listen_id->context,
+-			    listen_id->ps);
++			    listen_id->ps, ib_event->param.req_rcvd.qp_type);
+ 	if (IS_ERR(id))
+ 		goto err;
+ 
+@@ -1139,7 +1136,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
+ 	int ret;
+ 
+ 	id = rdma_create_id(listen_id->event_handler, listen_id->context,
+-			    listen_id->ps);
++			    listen_id->ps, IB_QPT_UD);
+ 	if (IS_ERR(id))
+ 		return NULL;
+ 
+@@ -1194,7 +1191,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
+ 	memset(&event, 0, sizeof event);
+ 	offset = cma_user_data_offset(listen_id->id.ps);
+ 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
+-	if (cma_is_ud_ps(listen_id->id.ps)) {
++	if (listen_id->id.qp_type == IB_QPT_UD) {
+ 		conn_id = cma_new_udp_id(&listen_id->id, ib_event);
+ 		event.param.ud.private_data = ib_event->private_data + offset;
+ 		event.param.ud.private_data_len =
+@@ -1230,8 +1227,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
+ 		 * while we're accessing the cm_id.
+ 		 */
+ 		mutex_lock(&lock);
+-		if (cma_comp(conn_id, RDMA_CM_CONNECT) &&
+-		    !cma_is_ud_ps(conn_id->id.ps))
++		if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD))
+ 			ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
+ 		mutex_unlock(&lock);
+ 		mutex_unlock(&conn_id->handler_mutex);
+@@ -1386,7 +1382,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
+ 	/* Create a new RDMA id for the new IW CM ID */
+ 	new_cm_id = rdma_create_id(listen_id->id.event_handler,
+ 				   listen_id->id.context,
+-				   RDMA_PS_TCP);
++				   RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(new_cm_id)) {
+ 		ret = -ENOMEM;
+ 		goto out;
+@@ -1535,7 +1531,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
+ 	struct rdma_cm_id *id;
+ 	int ret;
+ 
+-	id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps);
++	id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
++			    id_priv->id.qp_type);
+ 	if (IS_ERR(id))
+ 		return;
+ 
+@@ -2645,7 +2642,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+ 
+ 	switch (rdma_node_get_transport(id->device->node_type)) {
+ 	case RDMA_TRANSPORT_IB:
+-		if (cma_is_ud_ps(id->ps))
++		if (id->qp_type == IB_QPT_UD)
+ 			ret = cma_resolve_ib_udp(id_priv, conn_param);
+ 		else
+ 			ret = cma_connect_ib(id_priv, conn_param);
+@@ -2758,7 +2755,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+ 
+ 	switch (rdma_node_get_transport(id->device->node_type)) {
+ 	case RDMA_TRANSPORT_IB:
+-		if (cma_is_ud_ps(id->ps))
++		if (id->qp_type == IB_QPT_UD)
+ 			ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
+ 						conn_param->private_data,
+ 						conn_param->private_data_len);
+@@ -2819,7 +2816,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
+ 
+ 	switch (rdma_node_get_transport(id->device->node_type)) {
+ 	case RDMA_TRANSPORT_IB:
+-		if (cma_is_ud_ps(id->ps))
++		if (id->qp_type == IB_QPT_UD)
+ 			ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
+ 						private_data, private_data_len);
+ 		else
+diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
+index b3fa798..7109d5d 100644
+--- a/drivers/infiniband/core/ucma.c
++++ b/drivers/infiniband/core/ucma.c
+@@ -367,13 +367,28 @@ done:
+ 	return ret;
+ }
+ 
+-static ssize_t ucma_create_id(struct ucma_file *file,
+-				const char __user *inbuf,
+-				int in_len, int out_len)
++static int ucma_get_qp_type(struct rdma_ucm_create_id *cmd, enum ib_qp_type *qp_type)
++{
++	switch (cmd->ps) {
++	case RDMA_PS_TCP:
++		*qp_type = IB_QPT_RC;
++		return 0;
++	case RDMA_PS_UDP:
++	case RDMA_PS_IPOIB:
++		*qp_type = IB_QPT_UD;
++		return 0;
++	default:
++		return -EINVAL;
++	}
++}
++
++static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
++			      int in_len, int out_len)
+ {
+ 	struct rdma_ucm_create_id cmd;
+ 	struct rdma_ucm_create_id_resp resp;
+ 	struct ucma_context *ctx;
++	enum ib_qp_type qp_type;
+ 	int ret;
+ 
+ 	if (out_len < sizeof(resp))
+@@ -382,6 +397,10 @@ static ssize_t ucma_create_id(struct ucma_file *file,
+ 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ 		return -EFAULT;
+ 
++	ret = ucma_get_qp_type(&cmd, &qp_type);
++	if (ret)
++		return ret;
++
+ 	mutex_lock(&file->mut);
+ 	ctx = ucma_alloc_ctx(file);
+ 	mutex_unlock(&file->mut);
+@@ -389,7 +408,7 @@ static ssize_t ucma_create_id(struct ucma_file *file,
+ 		return -ENOMEM;
+ 
+ 	ctx->uid = cmd.uid;
+-	ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps);
++	ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type);
+ 	if (IS_ERR(ctx->cm_id)) {
+ 		ret = PTR_ERR(ctx->cm_id);
+ 		goto err1;
+diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
+index 98768657..ede1475 100644
+--- a/drivers/infiniband/ulp/iser/iser_verbs.c
++++ b/drivers/infiniband/ulp/iser/iser_verbs.c
+@@ -548,7 +548,7 @@ int iser_connect(struct iser_conn   *ib_conn,
+ 	iser_conn_get(ib_conn); /* ref ib conn's cma id */
+ 	ib_conn->cma_id = rdma_create_id(iser_cma_handler,
+ 					     (void *)ib_conn,
+-					     RDMA_PS_TCP);
++					     RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(ib_conn->cma_id)) {
+ 		err = PTR_ERR(ib_conn->cma_id);
+ 		iser_err("rdma_create_id failed: %d\n", err);
+diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h
+index d5b2265..26977c1 100644
+--- a/include/rdma/rdma_cm.h
++++ b/include/rdma/rdma_cm.h
+@@ -144,6 +144,7 @@ struct rdma_cm_id {
+ 	rdma_cm_event_handler	 event_handler;
+ 	struct rdma_route	 route;
+ 	enum rdma_port_space	 ps;
++	enum ib_qp_type		 qp_type;
+ 	u8			 port_num;
+ };
+ 
+@@ -154,9 +155,11 @@ struct rdma_cm_id {
+  *   returned rdma_id.
+  * @context: User specified context associated with the id.
+  * @ps: RDMA port space.
++ * @qp_type: type of queue pair associated with the id.
+  */
+ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+-				  void *context, enum rdma_port_space ps);
++				  void *context, enum rdma_port_space ps,
++				  enum ib_qp_type qp_type);
+ 
+ /**
+   * rdma_destroy_id - Destroys an RDMA identifier.
+diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
+index 150e0c4..3640e83 100644
+--- a/net/9p/trans_rdma.c
++++ b/net/9p/trans_rdma.c
+@@ -591,7 +591,8 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args)
+ 		return -ENOMEM;
+ 
+ 	/* Create the RDMA CM ID */
+-	rdma->cm_id = rdma_create_id(p9_cm_event_handler, client, RDMA_PS_TCP);
++	rdma->cm_id = rdma_create_id(p9_cm_event_handler, client, RDMA_PS_TCP,
++				     IB_QPT_RC);
+ 	if (IS_ERR(rdma->cm_id))
+ 		goto error;
+ 
+diff --git a/net/rds/ib.c b/net/rds/ib.c
+index cce19f9..3b83086 100644
+--- a/net/rds/ib.c
++++ b/net/rds/ib.c
+@@ -325,7 +325,7 @@ static int rds_ib_laddr_check(__be32 addr)
+ 	/* Create a CMA ID and try to bind it. This catches both
+ 	 * IB and iWARP capable NICs.
+ 	 */
+-	cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP);
++	cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(cm_id))
+ 		return PTR_ERR(cm_id);
+ 
+diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
+index ee369d2..fd453dd 100644
+--- a/net/rds/ib_cm.c
++++ b/net/rds/ib_cm.c
+@@ -587,7 +587,7 @@ int rds_ib_conn_connect(struct rds_connection *conn)
+ 	/* XXX I wonder what affect the port space has */
+ 	/* delegate cm event handler to rdma_transport */
+ 	ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+-				     RDMA_PS_TCP);
++				     RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(ic->i_cm_id)) {
+ 		ret = PTR_ERR(ic->i_cm_id);
+ 		ic->i_cm_id = NULL;
+diff --git a/net/rds/iw.c b/net/rds/iw.c
+index 5a9676f..f747484 100644
+--- a/net/rds/iw.c
++++ b/net/rds/iw.c
+@@ -226,7 +226,7 @@ static int rds_iw_laddr_check(__be32 addr)
+ 	/* Create a CMA ID and try to bind it. This catches both
+ 	 * IB and iWARP capable NICs.
+ 	 */
+-	cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP);
++	cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(cm_id))
+ 		return PTR_ERR(cm_id);
+ 
+diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c
+index 3a60a15..c12db66 100644
+--- a/net/rds/iw_cm.c
++++ b/net/rds/iw_cm.c
+@@ -522,7 +522,7 @@ int rds_iw_conn_connect(struct rds_connection *conn)
+ 	/* XXX I wonder what affect the port space has */
+ 	/* delegate cm event handler to rdma_transport */
+ 	ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+-				     RDMA_PS_TCP);
++				     RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(ic->i_cm_id)) {
+ 		ret = PTR_ERR(ic->i_cm_id);
+ 		ic->i_cm_id = NULL;
+diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c
+index 4195a05..f8760e1 100644
+--- a/net/rds/rdma_transport.c
++++ b/net/rds/rdma_transport.c
+@@ -158,7 +158,8 @@ static int rds_rdma_listen_init(void)
+ 	struct rdma_cm_id *cm_id;
+ 	int ret;
+ 
+-	cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP);
++	cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP,
++			       IB_QPT_RC);
+ 	if (IS_ERR(cm_id)) {
+ 		ret = PTR_ERR(cm_id);
+ 		printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+index 1a10dcd..afff475 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -695,7 +695,8 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+ 		return ERR_PTR(-ENOMEM);
+ 	xprt = &cma_xprt->sc_xprt;
+ 
+-	listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP);
++	listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP,
++				   IB_QPT_RC);
+ 	if (IS_ERR(listen_id)) {
+ 		ret = PTR_ERR(listen_id);
+ 		dprintk("svcrdma: rdma_create_id failed = %d\n", ret);
+diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
+index d4297dc..80f8da3 100644
+--- a/net/sunrpc/xprtrdma/verbs.c
++++ b/net/sunrpc/xprtrdma/verbs.c
+@@ -387,7 +387,7 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt,
+ 
+ 	init_completion(&ia->ri_done);
+ 
+-	id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP);
++	id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
+ 	if (IS_ERR(id)) {
+ 		rc = PTR_ERR(id);
+ 		dprintk("RPC:       %s: rdma_create_id() failed %i\n",
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_0013-RDMA-Increasing-RPCRDMA_MAX_DATA_SEGS.patch b/kernel_patches/fixes/nfsrdma_0013-RDMA-Increasing-RPCRDMA_MAX_DATA_SEGS.patch
new file mode 100644
index 0000000..2674c86
--- /dev/null
+++ b/kernel_patches/fixes/nfsrdma_0013-RDMA-Increasing-RPCRDMA_MAX_DATA_SEGS.patch
@@ -0,0 +1,31 @@
+From 2773395b34883fe54418de188733a63bb38e0ad6 Mon Sep 17 00:00:00 2001
+From: Steve Dickson <steved@redhat.com>
+Date: Thu, 21 Jul 2011 13:49:02 -0400
+Subject: [PATCH] RDMA: Increasing RPCRDMA_MAX_DATA_SEGS
+
+Our performance team has noticed that increasing
+RPCRDMA_MAX_DATA_SEGS from 8 to 64 significantly
+increases throughput when using the RDMA transport.
+
+Signed-off-by: Steve Dickson <steved@redhat.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+---
+ net/sunrpc/xprtrdma/xprt_rdma.h |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
+index cae761a..5d1cfe5 100644
+--- a/net/sunrpc/xprtrdma/xprt_rdma.h
++++ b/net/sunrpc/xprtrdma/xprt_rdma.h
+@@ -109,7 +109,7 @@ struct rpcrdma_ep {
+  */
+ 
+ /* temporary static scatter/gather max */
+-#define RPCRDMA_MAX_DATA_SEGS	(8)	/* max scatter/gather */
++#define RPCRDMA_MAX_DATA_SEGS	(64)	/* max scatter/gather */
+ #define RPCRDMA_MAX_SEGS 	(RPCRDMA_MAX_DATA_SEGS + 2) /* head+tail = 2 */
+ #define MAX_RPCRDMAHDR	(\
+ 	/* max supported RPC/RDMA header */ \
+-- 
+1.7.3.4
+
diff --git a/kernel_patches/fixes/nfsrdma_zz_0100_iova_truncate_fix.patch b/kernel_patches/fixes/nfsrdma_zz_0100_iova_truncate_fix.patch
deleted file mode 100644
index b6dc1bd..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_0100_iova_truncate_fix.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-xprtrdma: Do not truncate iova_start values in frmr registrations.
-
-From: Steve Wise <swise@opengridcomputing.com>
-
-A bad cast causes the iova_start, which in this case is a 64b DMA
-bus address, to be truncated on 32b systems.  This breaks frmrs on
-32b systems.  No cast is needed.
-
-Signed-off-by: Steve Wise <swise@opengridcomputing.com>
----
-
- net/sunrpc/xprtrdma/verbs.c |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
-index 465aafc..81d6257 100644
---- a/net/sunrpc/xprtrdma/verbs.c
-+++ b/net/sunrpc/xprtrdma/verbs.c
-@@ -1489,7 +1489,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
- 	memset(&frmr_wr, 0, sizeof frmr_wr);
- 	frmr_wr.opcode = IB_WR_FAST_REG_MR;
- 	frmr_wr.send_flags = 0;			/* unsignaled */
--	frmr_wr.wr.fast_reg.iova_start = (unsigned long)seg1->mr_dma;
-+	frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
- 	frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
- 	frmr_wr.wr.fast_reg.page_list_len = i;
- 	frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
diff --git a/kernel_patches/fixes/nfsrdma_zz_0700_dma_page_map_fix.patch b/kernel_patches/fixes/nfsrdma_zz_0700_dma_page_map_fix.patch
deleted file mode 100644
index db6634f..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_0700_dma_page_map_fix.patch
+++ /dev/null
@@ -1,293 +0,0 @@
-svcrdma: Change dma mapping logic to avoid the page_address kernel API
-
-From: Tom Tucker <tom@ogc.us>
-
-Not all pages are mapped into the kernel address space. This is
-particularly prevalent on systems with large amounts of memory and 32b
-systems where there is only 4GB of address space.
-
-There is logic in the send path that assumes that a page
-containing data to send to the client has a kva. This is not
-always the case and can result in data corruption.
-
-This patch changes the bus mapping logic to avoid page_address() where
-necessary and converts all calls from ib_dma_map_single to ib_dma_map_page
-in order to keep the map/unmap calls symmetric.
-
-signed-off-by: Tom Tucker <tom@ogc.us>
----
-
- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c  |   18 ++++---
- net/sunrpc/xprtrdma/svc_rdma_sendto.c    |   79 ++++++++++++++++++++++--------
- net/sunrpc/xprtrdma/svc_rdma_transport.c |   18 +++----
- 3 files changed, 77 insertions(+), 38 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-index 42a6f9f..57ae0b2 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-@@ -263,9 +263,9 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
- 	frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
- 	for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
- 		frmr->page_list->page_list[page_no] =
--			ib_dma_map_single(xprt->sc_cm_id->device,
--					  page_address(rqstp->rq_arg.pages[page_no]),
--					  PAGE_SIZE, DMA_FROM_DEVICE);
-+			ib_dma_map_page(xprt->sc_cm_id->device,
-+					rqstp->rq_arg.pages[page_no], 0,
-+					PAGE_SIZE, DMA_FROM_DEVICE);
- 		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
- 					 frmr->page_list->page_list[page_no]))
- 			goto fatal_err;
-@@ -309,17 +309,21 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
- 			     int count)
- {
- 	int i;
-+	unsigned long off;
- 
- 	ctxt->count = count;
- 	ctxt->direction = DMA_FROM_DEVICE;
- 	for (i = 0; i < count; i++) {
- 		ctxt->sge[i].length = 0; /* in case map fails */
- 		if (!frmr) {
-+			BUG_ON(0 == virt_to_page(vec[i].iov_base));
-+			off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
- 			ctxt->sge[i].addr =
--				ib_dma_map_single(xprt->sc_cm_id->device,
--						  vec[i].iov_base,
--						  vec[i].iov_len,
--						  DMA_FROM_DEVICE);
-+				ib_dma_map_page(xprt->sc_cm_id->device,
-+						virt_to_page(vec[i].iov_base),
-+						off,
-+						vec[i].iov_len,
-+						DMA_FROM_DEVICE);
- 			if (ib_dma_mapping_error(xprt->sc_cm_id->device,
- 						 ctxt->sge[i].addr))
- 				return -EINVAL;
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
-index f11be72..3619120 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
-@@ -70,8 +70,8 @@
-  * on extra page for the RPCRMDA header.
-  */
- static int fast_reg_xdr(struct svcxprt_rdma *xprt,
--		 struct xdr_buf *xdr,
--		 struct svc_rdma_req_map *vec)
-+			struct xdr_buf *xdr,
-+			struct svc_rdma_req_map *vec)
- {
- 	int sge_no;
- 	u32 sge_bytes;
-@@ -96,21 +96,25 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
- 	vec->count = 2;
- 	sge_no++;
- 
--	/* Build the FRMR */
-+	/* Map the XDR head */
- 	frmr->kva = frva;
- 	frmr->direction = DMA_TO_DEVICE;
- 	frmr->access_flags = 0;
- 	frmr->map_len = PAGE_SIZE;
- 	frmr->page_list_len = 1;
-+	page_off = (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
- 	frmr->page_list->page_list[page_no] =
--		ib_dma_map_single(xprt->sc_cm_id->device,
--				  (void *)xdr->head[0].iov_base,
--				  PAGE_SIZE, DMA_TO_DEVICE);
-+		ib_dma_map_page(xprt->sc_cm_id->device,
-+				virt_to_page((unsigned long)xdr->head[0].iov_base & PAGE_MASK),
-+				page_off,
-+				PAGE_SIZE - page_off,
-+				DMA_TO_DEVICE);
- 	if (ib_dma_mapping_error(xprt->sc_cm_id->device,
- 				 frmr->page_list->page_list[page_no]))
- 		goto fatal_err;
- 	atomic_inc(&xprt->sc_dma_used);
- 
-+	/* Map the XDR page list */
- 	page_off = xdr->page_base;
- 	page_bytes = xdr->page_len + page_off;
- 	if (!page_bytes)
-@@ -128,9 +132,9 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
- 		page_bytes -= sge_bytes;
- 
- 		frmr->page_list->page_list[page_no] =
--			ib_dma_map_single(xprt->sc_cm_id->device,
--					  page_address(page),
--					  PAGE_SIZE, DMA_TO_DEVICE);
-+			ib_dma_map_page(xprt->sc_cm_id->device,
-+					page, page_off,
-+					sge_bytes, DMA_TO_DEVICE);
- 		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
- 					 frmr->page_list->page_list[page_no]))
- 			goto fatal_err;
-@@ -166,8 +170,10 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
- 		vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
- 
- 		frmr->page_list->page_list[page_no] =
--			ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
--					  DMA_TO_DEVICE);
-+		    ib_dma_map_page(xprt->sc_cm_id->device, virt_to_page(va),
-+				    page_off,
-+				    PAGE_SIZE,
-+				    DMA_TO_DEVICE);
- 		if (ib_dma_mapping_error(xprt->sc_cm_id->device,
- 					 frmr->page_list->page_list[page_no]))
- 			goto fatal_err;
-@@ -245,6 +251,34 @@ static int map_xdr(struct svcxprt_rdma *xprt,
- 	return 0;
- }
- 
-+static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt,
-+			      struct xdr_buf *xdr,
-+			      u32 xdr_off, size_t len, int dir)
-+{
-+	struct page *page;
-+	dma_addr_t dma_addr;
-+	if (xdr_off < xdr->head[0].iov_len) {
-+		/* This offset is in the head */
-+		xdr_off += (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
-+		page = virt_to_page(xdr->head[0].iov_base + xdr_off);
-+	} else {
-+		xdr_off -= xdr->head[0].iov_len;
-+		if (xdr_off < xdr->page_len) {
-+			/* This offset is in the page list */
-+			page = xdr->pages[xdr_off >> PAGE_SHIFT];
-+			xdr_off &= ~PAGE_MASK;
-+		} else {
-+			/* This offset is in the tail */
-+			xdr_off -= xdr->page_len;
-+			xdr_off += (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
-+			page = virt_to_page(xdr->tail[0].iov_base);
-+		}
-+	}
-+	dma_addr = ib_dma_map_page(xprt->sc_cm_id->device, page, xdr_off,
-+				   min_t(size_t, PAGE_SIZE, len), dir);
-+	return dma_addr;
-+}
-+
- /* Assumptions:
-  * - We are using FRMR
-  *     - or -
-@@ -293,10 +327,9 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
- 		sge[sge_no].length = sge_bytes;
- 		if (!vec->frmr) {
- 			sge[sge_no].addr =
--				ib_dma_map_single(xprt->sc_cm_id->device,
--						  (void *)
--						  vec->sge[xdr_sge_no].iov_base + sge_off,
--						  sge_bytes, DMA_TO_DEVICE);
-+				dma_map_xdr(xprt, &rqstp->rq_res, xdr_off,
-+					    sge_bytes, DMA_TO_DEVICE);
-+			xdr_off += sge_bytes;
- 			if (ib_dma_mapping_error(xprt->sc_cm_id->device,
- 						 sge[sge_no].addr))
- 				goto err;
-@@ -494,7 +527,8 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
-  * In all three cases, this function prepares the RPCRDMA header in
-  * sge[0], the 'type' parameter indicates the type to place in the
-  * RPCRDMA header, and the 'byte_count' field indicates how much of
-- * the XDR to include in this RDMA_SEND.
-+ * the XDR to include in this RDMA_SEND. NB: The offset of the payload
-+ * to send is zero in the XDR.
-  */
- static int send_reply(struct svcxprt_rdma *rdma,
- 		      struct svc_rqst *rqstp,
-@@ -536,23 +570,24 @@ static int send_reply(struct svcxprt_rdma *rdma,
- 	ctxt->sge[0].lkey = rdma->sc_dma_lkey;
- 	ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
- 	ctxt->sge[0].addr =
--		ib_dma_map_single(rdma->sc_cm_id->device, page_address(page),
--				  ctxt->sge[0].length, DMA_TO_DEVICE);
-+	    ib_dma_map_page(rdma->sc_cm_id->device, page, 0,
-+			    ctxt->sge[0].length, DMA_TO_DEVICE);
- 	if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
- 		goto err;
- 	atomic_inc(&rdma->sc_dma_used);
- 
- 	ctxt->direction = DMA_TO_DEVICE;
- 
--	/* Determine how many of our SGE are to be transmitted */
-+	/* Map the payload indicated by 'byte_count' */
- 	for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
-+		int xdr_off = 0;
- 		sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
- 		byte_count -= sge_bytes;
- 		if (!vec->frmr) {
- 			ctxt->sge[sge_no].addr =
--				ib_dma_map_single(rdma->sc_cm_id->device,
--						  vec->sge[sge_no].iov_base,
--						  sge_bytes, DMA_TO_DEVICE);
-+				dma_map_xdr(rdma, &rqstp->rq_res, xdr_off,
-+					    sge_bytes, DMA_TO_DEVICE);
-+			xdr_off += sge_bytes;
- 			if (ib_dma_mapping_error(rdma->sc_cm_id->device,
- 						 ctxt->sge[sge_no].addr))
- 				goto err;
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
-index 5151f9f..fc3138b 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
-@@ -118,7 +118,7 @@ void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
- 		 */
- 		if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
- 			atomic_dec(&xprt->sc_dma_used);
--			ib_dma_unmap_single(xprt->sc_cm_id->device,
-+			ib_dma_unmap_page(xprt->sc_cm_id->device,
- 					    ctxt->sge[i].addr,
- 					    ctxt->sge[i].length,
- 					    ctxt->direction);
-@@ -500,8 +500,8 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
- 		BUG_ON(sge_no >= xprt->sc_max_sge);
- 		page = svc_rdma_get_page();
- 		ctxt->pages[sge_no] = page;
--		pa = ib_dma_map_single(xprt->sc_cm_id->device,
--				     page_address(page), PAGE_SIZE,
-+		pa = ib_dma_map_page(xprt->sc_cm_id->device,
-+				     page, 0, PAGE_SIZE,
- 				     DMA_FROM_DEVICE);
- 		if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
- 			goto err_put_ctxt;
-@@ -793,8 +793,8 @@ static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
- 		if (ib_dma_mapping_error(frmr->mr->device, addr))
- 			continue;
- 		atomic_dec(&xprt->sc_dma_used);
--		ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
--				    frmr->direction);
-+		ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
-+				  frmr->direction);
- 	}
- }
- 
-@@ -1269,7 +1269,7 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
- 				   atomic_read(&xprt->sc_sq_count) <
- 				   xprt->sc_sq_depth);
- 			if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
--				return 0;
-+				return -ENOTCONN;
- 			continue;
- 		}
- 		/* Take a transport ref for each WR posted */
-@@ -1315,8 +1315,8 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
- 	length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
- 
- 	/* Prepare SGE for local address */
--	sge.addr = ib_dma_map_single(xprt->sc_cm_id->device,
--				   page_address(p), PAGE_SIZE, DMA_FROM_DEVICE);
-+	sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
-+				   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
- 	if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
- 		put_page(p);
- 		return;
-@@ -1343,7 +1343,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
- 	if (ret) {
- 		dprintk("svcrdma: Error %d posting send for protocol error\n",
- 			ret);
--		ib_dma_unmap_single(xprt->sc_cm_id->device,
-+		ib_dma_unmap_page(xprt->sc_cm_id->device,
- 				  sge.addr, PAGE_SIZE,
- 				  DMA_FROM_DEVICE);
- 		svc_rdma_put_context(ctxt, 1);
diff --git a/kernel_patches/fixes/nfsrdma_zz_0800_error_path_fix.patch b/kernel_patches/fixes/nfsrdma_zz_0800_error_path_fix.patch
deleted file mode 100644
index 8592861..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_0800_error_path_fix.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-svcrdma: Cleanup DMA unmapping in error paths.
-
-From: Tom Tucker <tom@ogc.us>
-
-There are several error paths in the code that do not unmap DMA. This
-patch adds calls to svc_rdma_unmap_dma to free these DMA contexts.
-
-signed-off-by: Tom Tucker <tom@opengridcomputing.com>
----
-
- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c  |    1 +
- net/sunrpc/xprtrdma/svc_rdma_sendto.c    |    2 ++
- net/sunrpc/xprtrdma/svc_rdma_transport.c |   29 ++++++++++++++---------------
- 3 files changed, 17 insertions(+), 15 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-index 57ae0b2..5870719 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-@@ -496,6 +496,7 @@ next_sge:
- 			printk(KERN_ERR "svcrdma: Error %d posting RDMA_READ\n",
- 			       err);
- 			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
-+			svc_rdma_unmap_dma(ctxt);
- 			svc_rdma_put_context(ctxt, 0);
- 			goto out;
- 		}
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
-index 3619120..c99ac46 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
-@@ -366,6 +366,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
- 		goto err;
- 	return 0;
-  err:
-+	svc_rdma_unmap_dma(ctxt);
-+	svc_rdma_put_frmr(xprt, vec->frmr);
- 	svc_rdma_put_context(ctxt, 0);
- 	/* Fatal error, close transport */
- 	return -EIO;
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
-index d0ab1a2..b065115 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
-@@ -509,9 +509,9 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
- 		ctxt->sge[sge_no].addr = pa;
- 		ctxt->sge[sge_no].length = PAGE_SIZE;
- 		ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
-+		ctxt->count = sge_no + 1;
- 		buflen += PAGE_SIZE;
- 	}
--	ctxt->count = sge_no;
- 	recv_wr.next = NULL;
- 	recv_wr.sg_list = &ctxt->sge[0];
- 	recv_wr.num_sge = ctxt->count;
-@@ -527,6 +527,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
- 	return ret;
- 
-  err_put_ctxt:
-+	svc_rdma_unmap_dma(ctxt);
- 	svc_rdma_put_context(ctxt, 1);
- 	return -ENOMEM;
- }
-@@ -1301,7 +1302,6 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
- 			 enum rpcrdma_errcode err)
- {
- 	struct ib_send_wr err_wr;
--	struct ib_sge sge;
- 	struct page *p;
- 	struct svc_rdma_op_ctxt *ctxt;
- 	u32 *va;
-@@ -1314,26 +1314,27 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
- 	/* XDR encode error */
- 	length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
- 
-+	ctxt = svc_rdma_get_context(xprt);
-+	ctxt->direction = DMA_FROM_DEVICE;
-+	ctxt->count = 1;
-+	ctxt->pages[0] = p;
-+
- 	/* Prepare SGE for local address */
--	sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
--				   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
--	if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
-+	ctxt->sge[0].addr = ib_dma_map_page(xprt->sc_cm_id->device,
-+					    p, 0, length, DMA_FROM_DEVICE);
-+	if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
- 		put_page(p);
- 		return;
- 	}
- 	atomic_inc(&xprt->sc_dma_used);
--	sge.lkey = xprt->sc_dma_lkey;
--	sge.length = length;
--
--	ctxt = svc_rdma_get_context(xprt);
--	ctxt->count = 1;
--	ctxt->pages[0] = p;
-+	ctxt->sge[0].lkey = xprt->sc_dma_lkey;
-+	ctxt->sge[0].length = length;
- 
- 	/* Prepare SEND WR */
- 	memset(&err_wr, 0, sizeof err_wr);
- 	ctxt->wr_op = IB_WR_SEND;
- 	err_wr.wr_id = (unsigned long)ctxt;
--	err_wr.sg_list = &sge;
-+	err_wr.sg_list = ctxt->sge;
- 	err_wr.num_sge = 1;
- 	err_wr.opcode = IB_WR_SEND;
- 	err_wr.send_flags = IB_SEND_SIGNALED;
-@@ -1343,9 +1344,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
- 	if (ret) {
- 		dprintk("svcrdma: Error %d posting send for protocol error\n",
- 			ret);
--		ib_dma_unmap_page(xprt->sc_cm_id->device,
--				  sge.addr, PAGE_SIZE,
--				  DMA_FROM_DEVICE);
-+		svc_rdma_unmap_dma(ctxt);
- 		svc_rdma_put_context(ctxt, 1);
- 	}
- }
diff --git a/kernel_patches/fixes/nfsrdma_zz_1400_frmr_sq_depth_fix.patch b/kernel_patches/fixes/nfsrdma_zz_1400_frmr_sq_depth_fix.patch
deleted file mode 100644
index fb33ea7..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_1400_frmr_sq_depth_fix.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-rpcrdma: Fix SQ size calculation when memreg is FRMR
-
-From: Tom Tucker <tom@ogc.us>
-
-This patch updates the computation to include the worst case situation
-where three FRMR are required to map a single RPC REQ.
-
-Signed-off-by: Tom Tucker <tom@ogc.us>
-Signed-off-by: Vu Pham <vu@mellanox.com>
----
-
- net/sunrpc/xprtrdma/rpc_rdma.c |    2 ++
- net/sunrpc/xprtrdma/verbs.c    |   20 ++++++++++++++++----
- 2 files changed, 18 insertions(+), 4 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
-index e5e28d1..2ac3f6e 100644
---- a/net/sunrpc/xprtrdma/rpc_rdma.c
-+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
-@@ -249,6 +249,8 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
- 	req->rl_nchunks = nchunks;
- 
- 	BUG_ON(nchunks == 0);
-+	BUG_ON((r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR)
-+	       && (nchunks > 3));
- 
- 	/*
- 	 * finish off header. If write, marshal discrim and nchunks.
-diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
-index 465aafc..be1ad9d 100644
---- a/net/sunrpc/xprtrdma/verbs.c
-+++ b/net/sunrpc/xprtrdma/verbs.c
-@@ -649,10 +649,22 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
- 	ep->rep_attr.cap.max_send_wr = cdata->max_requests;
- 	switch (ia->ri_memreg_strategy) {
- 	case RPCRDMA_FRMR:
--		/* Add room for frmr register and invalidate WRs */
--		ep->rep_attr.cap.max_send_wr *= 3;
--		if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr)
--			return -EINVAL;
-+		/* Add room for frmr register and invalidate WRs.
-+		 * 1. FRMR reg WR for head
-+		 * 2. FRMR invalidate WR for head
-+		 * 3. FRMR reg WR for pagelist
-+		 * 4. FRMR invalidate WR for pagelist
-+		 * 5. FRMR reg WR for tail
-+		 * 6. FRMR invalidate WR for tail
-+		 * 7. The RDMA_SEND WR
-+		 */
-+		ep->rep_attr.cap.max_send_wr *= 7;
-+		if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) {
-+			cdata->max_requests = devattr.max_qp_wr / 7;
-+			if (!cdata->max_requests)
-+				return -EINVAL;
-+			ep->rep_attr.cap.max_send_wr = cdata->max_requests * 7;
-+		}
- 		break;
- 	case RPCRDMA_MEMWINDOWS_ASYNC:
- 	case RPCRDMA_MEMWINDOWS:
diff --git a/kernel_patches/fixes/nfsrdma_zz_1500_remove_invalid_bug_on.patch b/kernel_patches/fixes/nfsrdma_zz_1500_remove_invalid_bug_on.patch
deleted file mode 100644
index c1e7d62..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_1500_remove_invalid_bug_on.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-rpcrdma: Remove invalid BUG_ON in rpcrdma_reply_handler
-
-From: Tom Tucker <tom@ogc.us>
-
-The rpcrdma_reply_handler has a BUG_ON that checks if a reply buffer is
-already attached to the request. Since the reply buffer is reset to null in
-rpcrdma_ep_post, the theory was that it couldn't be non-null. However, if
-this request is retransmitted, (e.g. due to a timeout), then there is a 
-race condition between this function and xprt_rdma_send_request where a new
-reply buffer is allocated and assigned to this request -- making the BUG_ON
-condition true.
-
-The first check in the BUG_ON (!req) is also invalid since the req is 
-assigned from container_of on a pointer that has already been checked for
-null, and therefore, req can't possibly be null.
-
-The fix is to remove the BUG_ON and replace it with code that posts and/or
-frees the unneeded reply buffer.
-
-Signed-off-by: Tom Tucker <tom@ogc.us>
----
-
- net/sunrpc/xprtrdma/rpc_rdma.c |   12 +++++++++++-
- 1 files changed, 11 insertions(+), 1 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
-index 2ac3f6e..6b70793 100644
---- a/net/sunrpc/xprtrdma/rpc_rdma.c
-+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
-@@ -778,7 +778,17 @@ repost:
- 		"                   RPC request 0x%p xid 0x%08x\n",
- 			__func__, rep, req, rqst, headerp->rm_xid);
- 
--	BUG_ON(!req || req->rl_reply);
-+	/*
-+	 * If this req was re-transmited, rl_reply will point to a new
-+	 * buffer allocated in xprt_rdma_send_request. Post/free it.
-+	 */
-+	if (req->rl_reply) {
-+		struct rpcrdma_rep *_rep = req->rl_reply;
-+                req->rl_reply = NULL;
-+                _rep->rr_func = rpcrdma_reply_handler;
-+                if (rpcrdma_ep_post_recv(&r_xprt->rx_ia, &r_xprt->rx_ep, _rep))
-+                        rpcrdma_recv_buffer_put(_rep);
-+	}
- 
- 	/* from here on, the reply is no longer an orphan */
- 	req->rl_reply = rep;
diff --git a/kernel_patches/fixes/nfsrdma_zz_1700_frmr_inv_fix.patch b/kernel_patches/fixes/nfsrdma_zz_1700_frmr_inv_fix.patch
deleted file mode 100644
index 20e8f25..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_1700_frmr_inv_fix.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-rpcrdma: Fix FRMR invalidate logic
-
-From: Tom Tucker <tom@ogc.us>
-
-The FRMR validate/invalidate logic was not resilient to transport errors
-that may cause FRMR INVALIDATE WQE to be flushed and not processed by the
-adapter. Since FRMR are retained across connections, this would result in
-FRMR registration failures when the FRMR was reused on
-another connection and result in an error and termination.
-
-Since invalidating an already invalid FRMR is not an error, moved the
-invalidate step to immediately before registration. This guarantees that
-the FRMR is always in the correct state prior to registration.
-
-Signed-off-by: Tom Tucker <tom@ogc.us>
----
-
- net/sunrpc/xprtrdma/verbs.c |   38 ++++++++++++++++++++++++--------------
- 1 files changed, 24 insertions(+), 14 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
-index be1ad9d..5f9fc28 100644
---- a/net/sunrpc/xprtrdma/verbs.c
-+++ b/net/sunrpc/xprtrdma/verbs.c
-@@ -1462,6 +1462,23 @@ rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
- 				seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
- }
- 
-+static void rpcrdma_deregister_frmr(struct rpcrdma_mr_seg *seg,
-+				   struct rpcrdma_ia *ia)
-+{
-+        struct ib_send_wr invalidate_wr, *bad_wr;
-+        int rc;
-+
-+        memset(&invalidate_wr, 0, sizeof invalidate_wr);
-+        invalidate_wr.opcode = IB_WR_LOCAL_INV;
-+        invalidate_wr.send_flags = 0;                   /* unsignaled */
-+        invalidate_wr.ex.invalidate_rkey = seg->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
-+
-+        rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
-+        if (rc)
-+                dprintk("RPC:       %s: failed ib_post_send for invalidate,"
-+                        " status %i\n", __func__, rc);
-+}
-+
- static int
- rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
- 			int *nsegs, int writing, struct rpcrdma_ia *ia,
-@@ -1493,6 +1510,12 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
- 	dprintk("RPC:       %s: Using frmr %p to map %d segments\n",
- 		__func__, seg1->mr_chunk.rl_mw, i);
- 
-+        /*
-+	 * Lazy invalidate the FRMR. It is not an error to invalidate
-+	 * an invalid FRMR.
-+	 */
-+        rpcrdma_deregister_frmr(seg1, ia);
-+
- 	/* Bump the key */
- 	key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF);
- 	ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key);
-@@ -1534,23 +1557,10 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg,
- 			struct rpcrdma_ia *ia, struct rpcrdma_xprt *r_xprt)
- {
- 	struct rpcrdma_mr_seg *seg1 = seg;
--	struct ib_send_wr invalidate_wr, *bad_wr;
--	int rc;
--
- 	while (seg1->mr_nsegs--)
- 		rpcrdma_unmap_one(ia, seg++);
- 
--	memset(&invalidate_wr, 0, sizeof invalidate_wr);
--	invalidate_wr.opcode = IB_WR_LOCAL_INV;
--	invalidate_wr.send_flags = 0;			/* unsignaled */
--	invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
--	DECR_CQCOUNT(&r_xprt->rx_ep);
--
--	rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
--	if (rc)
--		dprintk("RPC:       %s: failed ib_post_send for invalidate,"
--			" status %i\n", __func__, rc);
--	return rc;
-+	return 0;
- }
- 
- static int
diff --git a/kernel_patches/fixes/nfsrdma_zz_1800_fix_respages_in_read_complete.patch b/kernel_patches/fixes/nfsrdma_zz_1800_fix_respages_in_read_complete.patch
deleted file mode 100644
index 77926b7..0000000
--- a/kernel_patches/fixes/nfsrdma_zz_1800_fix_respages_in_read_complete.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-svcrdma: Fix rq_respages start computation
-
-From: Tom Tucker <tom@ogc.us>
-
-The rq_respages start address computation is off by 1 in
-rdma_read_complete. This can cause a response to run off the end of the
-allocated array.
-
-Signed-off-by: David Wilder <dwilder@us.ibm.com>
-Signed-off-by: Tom Tucker <tom@ogc.us>
----
-
- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-
-diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-index 42a6f9f..8ea0f86 100644
---- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
-@@ -543,7 +543,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp,
- 	rqstp->rq_arg.page_base = head->arg.page_base;
- 
- 	/* rq_respages starts after the last arg page */
--	rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
-+	rqstp->rq_respages = &rqstp->rq_pages[head->count];
- 	rqstp->rq_resused = 0;
- 
- 	/* Rebuild rq_arg head and tail. */
-- 
1.7.3.4

