Merge branch 'gup_flag-cleanups'
[cascardo/linux.git] / net / sunrpc / xprtrdma / svc_rdma_transport.c
index eb2857f..6864fb9 100644 (file)
@@ -198,6 +198,7 @@ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
 
 out:
        ctxt->count = 0;
+       ctxt->mapped_sges = 0;
        ctxt->frmr = NULL;
        return ctxt;
 
@@ -221,22 +222,27 @@ out_empty:
 void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
 {
        struct svcxprt_rdma *xprt = ctxt->xprt;
-       int i;
-       for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
+       struct ib_device *device = xprt->sc_cm_id->device;
+       u32 lkey = xprt->sc_pd->local_dma_lkey;
+       unsigned int i, count;
+
+       for (count = 0, i = 0; i < ctxt->mapped_sges; i++) {
                /*
                 * Unmap the DMA addr in the SGE if the lkey matches
                 * the local_dma_lkey, otherwise, ignore it since it is
                 * an FRMR lkey and will be unmapped later when the
                 * last WR that uses it completes.
                 */
-               if (ctxt->sge[i].lkey == xprt->sc_pd->local_dma_lkey) {
-                       atomic_dec(&xprt->sc_dma_used);
-                       ib_dma_unmap_page(xprt->sc_cm_id->device,
+               if (ctxt->sge[i].lkey == lkey) {
+                       count++;
+                       ib_dma_unmap_page(device,
                                            ctxt->sge[i].addr,
                                            ctxt->sge[i].length,
                                            ctxt->direction);
                }
        }
+       ctxt->mapped_sges = 0;
+       atomic_sub(count, &xprt->sc_dma_used);
 }
 
 void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
@@ -600,7 +606,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt, gfp_t flags)
                                     DMA_FROM_DEVICE);
                if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
                        goto err_put_ctxt;
-               atomic_inc(&xprt->sc_dma_used);
+               svc_rdma_count_mappings(xprt, ctxt);
                ctxt->sge[sge_no].addr = pa;
                ctxt->sge[sge_no].length = PAGE_SIZE;
                ctxt->sge[sge_no].lkey = xprt->sc_pd->local_dma_lkey;
@@ -642,6 +648,26 @@ int svc_rdma_repost_recv(struct svcxprt_rdma *xprt, gfp_t flags)
        return ret;
 }
 
+static void
+svc_rdma_parse_connect_private(struct svcxprt_rdma *newxprt,
+                              struct rdma_conn_param *param)
+{
+       const struct rpcrdma_connect_private *pmsg = param->private_data;
+
+       if (pmsg &&
+           pmsg->cp_magic == rpcrdma_cmp_magic &&
+           pmsg->cp_version == RPCRDMA_CMP_VERSION) {
+               newxprt->sc_snd_w_inv = pmsg->cp_flags &
+                                       RPCRDMA_CMP_F_SND_W_INV_OK;
+
+               dprintk("svcrdma: client send_size %u, recv_size %u "
+                       "remote inv %ssupported\n",
+                       rpcrdma_decode_buffer_size(pmsg->cp_send_size),
+                       rpcrdma_decode_buffer_size(pmsg->cp_recv_size),
+                       newxprt->sc_snd_w_inv ? "" : "un");
+       }
+}
+
 /*
  * This function handles the CONNECT_REQUEST event on a listening
  * endpoint. It is passed the cma_id for the _new_ connection. The context in
@@ -653,7 +679,8 @@ int svc_rdma_repost_recv(struct svcxprt_rdma *xprt, gfp_t flags)
  * will call the recvfrom method on the listen xprt which will accept the new
  * connection.
  */
-static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird)
+static void handle_connect_req(struct rdma_cm_id *new_cma_id,
+                              struct rdma_conn_param *param)
 {
        struct svcxprt_rdma *listen_xprt = new_cma_id->context;
        struct svcxprt_rdma *newxprt;
@@ -669,9 +696,10 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird)
        new_cma_id->context = newxprt;
        dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n",
                newxprt, newxprt->sc_cm_id, listen_xprt);
+       svc_rdma_parse_connect_private(newxprt, param);
 
        /* Save client advertised inbound read limit for use later in accept. */
-       newxprt->sc_ord = client_ird;
+       newxprt->sc_ord = param->initiator_depth;
 
        /* Set the local and remote addresses in the transport */
        sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
@@ -706,8 +734,7 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
                dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
                        "event = %s (%d)\n", cma_id, cma_id->context,
                        rdma_event_msg(event->event), event->event);
-               handle_connect_req(cma_id,
-                                  event->param.conn.initiator_depth);
+               handle_connect_req(cma_id, &event->param.conn);
                break;
 
        case RDMA_CM_EVENT_ESTABLISHED:
@@ -941,6 +968,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        struct svcxprt_rdma *listen_rdma;
        struct svcxprt_rdma *newxprt = NULL;
        struct rdma_conn_param conn_param;
+       struct rpcrdma_connect_private pmsg;
        struct ib_qp_init_attr qp_attr;
        struct ib_device *dev;
        unsigned int i;
@@ -1070,7 +1098,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
                        dev->attrs.max_fast_reg_page_list_len;
                newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
                newxprt->sc_reader = rdma_read_chunk_frmr;
-       }
+       } else
+               newxprt->sc_snd_w_inv = false;
 
        /*
         * Determine if a DMA MR is required and if so, what privs are required
@@ -1094,11 +1123,20 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        /* Swap out the handler */
        newxprt->sc_cm_id->event_handler = rdma_cma_handler;
 
+       /* Construct RDMA-CM private message */
+       pmsg.cp_magic = rpcrdma_cmp_magic;
+       pmsg.cp_version = RPCRDMA_CMP_VERSION;
+       pmsg.cp_flags = 0;
+       pmsg.cp_send_size = pmsg.cp_recv_size =
+               rpcrdma_encode_buffer_size(newxprt->sc_max_req_size);
+
        /* Accept Connection */
        set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
        memset(&conn_param, 0, sizeof conn_param);
        conn_param.responder_resources = 0;
        conn_param.initiator_depth = newxprt->sc_ord;
+       conn_param.private_data = &pmsg;
+       conn_param.private_data_len = sizeof(pmsg);
        ret = rdma_accept(newxprt->sc_cm_id, &conn_param);
        if (ret) {
                dprintk("svcrdma: failed to accept new connection, ret=%d\n",