xprtrdma: Fix error handling in rpcrdma_prepare_msg_sges()
authorChuck Lever <chuck.lever@oracle.com>
Fri, 20 Oct 2017 14:47:47 +0000 (10:47 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Fri, 17 Nov 2017 18:47:55 +0000 (13:47 -0500)
When this function fails, it needs to undo the DMA mappings it's
done so far. Otherwise these are leaked.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
net/sunrpc/xprtrdma/rpc_rdma.c

index 3c9255824d94f3e493323744f634d596ed821635..4f6c5395d198d484689340cccf29b1d339ae15a6 100644 (file)
@@ -511,6 +511,28 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        return 0;
 }
 
+/**
+ * rpcrdma_unmap_sges - DMA-unmap Send buffers
+ * @ia: interface adapter (device)
+ * @req: req with possibly some SGEs to be DMA unmapped
+ *
+ */
+void
+rpcrdma_unmap_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
+{
+       struct ib_sge *sge;
+       unsigned int count;
+
+       /* The first two SGEs contain the transport header and
+        * the inline buffer. These are always left mapped so
+        * they can be cheaply re-used.
+        */
+       sge = &req->rl_send_sge[2];
+       for (count = req->rl_mapped_sges; count--; sge++)
+               ib_dma_unmap_page(ia->ri_device,
+                                 sge->addr, sge->length, DMA_TO_DEVICE);
+}
+
 /* Prepare the RPC-over-RDMA header SGE.
  */
 static bool
@@ -641,10 +663,12 @@ out:
        return true;
 
 out_mapping_overflow:
+       rpcrdma_unmap_sges(ia, req);
        pr_err("rpcrdma: too many Send SGEs (%u)\n", sge_no);
        return false;
 
 out_mapping_err:
+       rpcrdma_unmap_sges(ia, req);
        pr_err("rpcrdma: Send mapping error\n");
        return false;
 }
@@ -671,20 +695,6 @@ out_map:
        return false;
 }
 
-void
-rpcrdma_unmap_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
-{
-       struct ib_device *device = ia->ri_device;
-       struct ib_sge *sge;
-       int count;
-
-       sge = &req->rl_send_sge[2];
-       for (count = req->rl_mapped_sges; count--; sge++)
-               ib_dma_unmap_page(device, sge->addr, sge->length,
-                                 DMA_TO_DEVICE);
-       req->rl_mapped_sges = 0;
-}
-
 /**
  * rpcrdma_marshal_req - Marshal and send one RPC request
  * @r_xprt: controlling transport