svcrdma: Add back svcxprt_rdma::sc_read_complete_q
[linux-2.6-microblaze.git] / net / sunrpc / xprtrdma / svc_rdma_recvfrom.c
index e363cb1..2de9471 100644 (file)
@@ -382,6 +382,10 @@ void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma)
 {
        struct svc_rdma_recv_ctxt *ctxt;
 
+       while ((ctxt = svc_rdma_next_recv_ctxt(&rdma->sc_read_complete_q))) {
+               list_del(&ctxt->rc_list);
+               svc_rdma_recv_ctxt_put(rdma, ctxt);
+       }
        while ((ctxt = svc_rdma_next_recv_ctxt(&rdma->sc_rq_dto_q))) {
                list_del(&ctxt->rc_list);
                svc_rdma_recv_ctxt_put(rdma, ctxt);
@@ -763,6 +767,30 @@ static bool svc_rdma_is_reverse_direction_reply(struct svc_xprt *xprt,
        return true;
 }
 
+static noinline void svc_rdma_read_complete(struct svc_rqst *rqstp,
+                                           struct svc_rdma_recv_ctxt *ctxt)
+{
+       int i;
+
+       /* Transfer the Read chunk pages into @rqstp.rq_pages, replacing
+        * the rq_pages that were already allocated for this rqstp.
+        */
+       release_pages(rqstp->rq_respages, ctxt->rc_page_count);
+       for (i = 0; i < ctxt->rc_page_count; i++)
+               rqstp->rq_pages[i] = ctxt->rc_pages[i];
+
+       /* Update @rqstp's result send buffer to start after the
+        * last page in the RDMA Read payload.
+        */
+       rqstp->rq_respages = &rqstp->rq_pages[ctxt->rc_page_count];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
+
+       /* Prevent svc_rdma_recv_ctxt_put() from releasing the
+        * pages in ctxt::rc_pages a second time.
+        */
+       ctxt->rc_page_count = 0;
+}
+
 /**
  * svc_rdma_recvfrom - Receive an RPC call
  * @rqstp: request structure into which to receive an RPC Call
@@ -807,8 +835,14 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
 
        rqstp->rq_xprt_ctxt = NULL;
 
-       ctxt = NULL;
        spin_lock(&rdma_xprt->sc_rq_dto_lock);
+       ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_read_complete_q);
+       if (ctxt) {
+               list_del(&ctxt->rc_list);
+               spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock);
+               svc_rdma_read_complete(rqstp, ctxt);
+               goto complete;
+       }
        ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_rq_dto_q);
        if (ctxt)
                list_del(&ctxt->rc_list);
@@ -846,6 +880,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
                        goto out_readfail;
        }
 
+complete:
        rqstp->rq_xprt_ctxt = ctxt;
        rqstp->rq_prot = IPPROTO_MAX;
        svc_xprt_copy_addrs(rqstp, xprt);