Merge tag 'nfs-for-4.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[firefly-linux-kernel-4.4.55.git] / net / sunrpc / xprtrdma / svc_rdma_transport.c
index fcc3eb80c265456d88bfe733ac9d6c1301d24e92..b348b4adef29a48246709cc7f32cf576865753eb 100644 (file)
@@ -56,6 +56,7 @@
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
+static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *, int);
 static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
                                        struct net *net,
                                        struct sockaddr *sa, int salen,
@@ -95,6 +96,63 @@ struct svc_xprt_class svc_rdma_class = {
        .xcl_ident = XPRT_TRANSPORT_RDMA,
 };
 
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
+static struct svc_xprt *svc_rdma_bc_create(struct svc_serv *, struct net *,
+                                          struct sockaddr *, int, int);
+static void svc_rdma_bc_detach(struct svc_xprt *);
+static void svc_rdma_bc_free(struct svc_xprt *);
+
+static struct svc_xprt_ops svc_rdma_bc_ops = {
+       .xpo_create = svc_rdma_bc_create,
+       .xpo_detach = svc_rdma_bc_detach,
+       .xpo_free = svc_rdma_bc_free,
+       .xpo_prep_reply_hdr = svc_rdma_prep_reply_hdr,
+       .xpo_secure_port = svc_rdma_secure_port,
+};
+
+struct svc_xprt_class svc_rdma_bc_class = {
+       .xcl_name = "rdma-bc",
+       .xcl_owner = THIS_MODULE,
+       .xcl_ops = &svc_rdma_bc_ops,
+       .xcl_max_payload = (1024 - RPCRDMA_HDRLEN_MIN)
+};
+
+static struct svc_xprt *svc_rdma_bc_create(struct svc_serv *serv,
+                                          struct net *net,
+                                          struct sockaddr *sa, int salen,
+                                          int flags)
+{
+       struct svcxprt_rdma *cma_xprt;
+       struct svc_xprt *xprt;
+
+       cma_xprt = rdma_create_xprt(serv, 0);
+       if (!cma_xprt)
+               return ERR_PTR(-ENOMEM);
+       xprt = &cma_xprt->sc_xprt;
+
+       svc_xprt_init(net, &svc_rdma_bc_class, xprt, serv);
+       serv->sv_bc_xprt = xprt;
+
+       dprintk("svcrdma: %s(%p)\n", __func__, xprt);
+       return xprt;
+}
+
+static void svc_rdma_bc_detach(struct svc_xprt *xprt)
+{
+       dprintk("svcrdma: %s(%p)\n", __func__, xprt);
+}
+
+static void svc_rdma_bc_free(struct svc_xprt *xprt)
+{
+       struct svcxprt_rdma *rdma =
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+
+       dprintk("svcrdma: %s(%p)\n", __func__, xprt);
+       if (xprt)
+               kfree(rdma);
+}
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
+
 struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
 {
        struct svc_rdma_op_ctxt *ctxt;
@@ -692,8 +750,8 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
        if (!cma_xprt)
                return ERR_PTR(-ENOMEM);
 
-       listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP,
-                                  IB_QPT_RC);
+       listen_id = rdma_create_id(&init_net, 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);
@@ -732,7 +790,7 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
 static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
 {
        struct ib_mr *mr;
-       struct ib_fast_reg_page_list *pl;
+       struct scatterlist *sg;
        struct svc_rdma_fastreg_mr *frmr;
        u32 num_sg;
 
@@ -745,13 +803,14 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
        if (IS_ERR(mr))
                goto err_free_frmr;
 
-       pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
-                                        num_sg);
-       if (IS_ERR(pl))
+       sg = kcalloc(RPCSVC_MAXPAGES, sizeof(*sg), GFP_KERNEL);
+       if (!sg)
                goto err_free_mr;
 
+       sg_init_table(sg, RPCSVC_MAXPAGES);
+
        frmr->mr = mr;
-       frmr->page_list = pl;
+       frmr->sg = sg;
        INIT_LIST_HEAD(&frmr->frmr_list);
        return frmr;
 
@@ -771,8 +830,8 @@ static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
                frmr = list_entry(xprt->sc_frmr_q.next,
                                  struct svc_rdma_fastreg_mr, frmr_list);
                list_del_init(&frmr->frmr_list);
+               kfree(frmr->sg);
                ib_dereg_mr(frmr->mr);
-               ib_free_fast_reg_page_list(frmr->page_list);
                kfree(frmr);
        }
 }
@@ -786,8 +845,7 @@ struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
                frmr = list_entry(rdma->sc_frmr_q.next,
                                  struct svc_rdma_fastreg_mr, frmr_list);
                list_del_init(&frmr->frmr_list);
-               frmr->map_len = 0;
-               frmr->page_list_len = 0;
+               frmr->sg_nents = 0;
        }
        spin_unlock_bh(&rdma->sc_frmr_q_lock);
        if (frmr)
@@ -796,25 +854,13 @@ struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
        return rdma_alloc_frmr(rdma);
 }
 
-static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
-                          struct svc_rdma_fastreg_mr *frmr)
-{
-       int page_no;
-       for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
-               dma_addr_t addr = frmr->page_list->page_list[page_no];
-               if (ib_dma_mapping_error(frmr->mr->device, addr))
-                       continue;
-               atomic_dec(&xprt->sc_dma_used);
-               ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
-                                 frmr->direction);
-       }
-}
-
 void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
                       struct svc_rdma_fastreg_mr *frmr)
 {
        if (frmr) {
-               frmr_unmap_dma(rdma, frmr);
+               ib_dma_unmap_sg(rdma->sc_cm_id->device,
+                               frmr->sg, frmr->sg_nents, frmr->direction);
+               atomic_dec(&rdma->sc_dma_used);
                spin_lock_bh(&rdma->sc_frmr_q_lock);
                WARN_ON_ONCE(!list_empty(&frmr->frmr_list));
                list_add(&frmr->frmr_list, &rdma->sc_frmr_q);