summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2016-09-13 17:52:50 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-18 12:51:50 +0300
commit07c4cbe0134111fe10e6eab2a16a6d23c5134392 (patch)
tree6d2c7e0b03f818e3009fa9a9e3f53e146f0c4860 /include/linux
parent4131e00a436e1f237841f996a239ea081da0761e (diff)
downloadlinux-07c4cbe0134111fe10e6eab2a16a6d23c5134392.tar.xz
svcrdma: Tail iovec leaves an orphaned DMA mapping
commit cace564f8b6260e806f5e28d7f192fd0e0c603ed upstream. The ctxt's count field is overloaded to mean the number of pages in the ctxt->page array and the number of SGEs in the ctxt->sge array. Typically these two numbers are the same. However, when an inline RPC reply is constructed from an xdr_buf with a tail iovec, the head and tail often occupy the same page, but each are DMA mapped independently. In that case, ->count equals the number of pages, but it does not equal the number of SGEs. There's one more SGE, for the tail iovec. Hence there is one more DMA mapping than there are pages in the ctxt->page array. This isn't a real problem until the server's iommu is enabled. Then each RPC reply that has content in that iovec orphans a DMA mapping that consists of real resources. krb5i and krb5p always populate that tail iovec. After a couple million sent krb5i/p RPC replies, the NFS server starts behaving erratically. Reboot is needed to clear the problem. Fixes: 9d11b51ce7c1 ("svcrdma: Fix send_reply() scatter/gather set-up") Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/sunrpc/svc_rdma.h9
1 files changed, 9 insertions, 0 deletions
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index d6917b896d3a..3584bc8864c4 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -86,6 +86,7 @@ struct svc_rdma_op_ctxt {
unsigned long flags;
enum dma_data_direction direction;
int count;
+ unsigned int mapped_sges;
struct ib_sge sge[RPCSVC_MAXPAGES];
struct page *pages[RPCSVC_MAXPAGES];
};
@@ -193,6 +194,14 @@ struct svcxprt_rdma {
#define RPCSVC_MAXPAYLOAD_RDMA RPCSVC_MAXPAYLOAD
+/* Track DMA maps for this transport and context */
+static inline void svc_rdma_count_mappings(struct svcxprt_rdma *rdma,
+ struct svc_rdma_op_ctxt *ctxt)
+{
+ ctxt->mapped_sges++;
+ atomic_inc(&rdma->sc_dma_used);
+}
+
/* svc_rdma_backchannel.c */
extern int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt,
struct rpcrdma_msg *rmsgp,