[pnfs] [PATCH 09/11] Update xs_tcp_read_request() to handle back channel callbacks.

ricardo.labiaga at netapp.com ricardo.labiaga at netapp.com
Tue Nov 27 23:25:19 EST 2007


Traditionally NFS clients only expect RPC replies on the open connections.  With
NFSv4.1, callbacks can arrive over an existing open connections.
Update xs_tcp_read_request() to queue callback requests onto a queue where
the callback service (a separate thread) is listening for the processing.
Original code by Rahul Iyer (iyer at netapp.com).

Signed-off-by: Ricardo Labiaga <ricardo.labiaga at netapp.com>
---
 net/sunrpc/xprtsock.c |   65 ++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 8347aac..0eda706 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -35,6 +35,9 @@
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/xprtsock.h>
 #include <linux/file.h>
+#ifdef CONFIG_NFS_V4_1
+#include <linux/sunrpc/bc_xprt.h>
+#endif
 
 #include <net/sock.h>
 #include <net/checksum.h>
@@ -960,16 +963,34 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea
 	struct xdr_buf *rcvbuf;
 	size_t len;
 	ssize_t r;
-
-	/* Find and lock the request corresponding to this xid */
-	spin_lock(&xprt->transport_lock);
-	req = xprt_lookup_rqst(xprt, transport->tcp_xid);
-	if (!req) {
-		transport->tcp_flags &= ~TCP_RCV_COPY_DATA;
-		dprintk("RPC:       XID %08x request not found!\n",
-				ntohl(transport->tcp_xid));
-		spin_unlock(&xprt->transport_lock);
-		return;
+	u32 calldir;
+
+	calldir = ntohl(transport->tcp_calldir);
+	if (calldir == RPC_REPLY) {
+		/* Find and lock the request corresponding to this xid */
+		spin_lock(&xprt->transport_lock);
+		req = xprt_lookup_rqst(xprt, transport->tcp_xid);
+		if (!req) {
+			dprintk("RPC:       XID %08x request not found!\n",
+					ntohl(transport->tcp_xid));
+			goto error;
+		}
+	} else {
+		/* RPC_CALL */
+		if (xprt->bc_mempool) {
+			req = xprt_alloc_bc_request(xprt);
+		} else {
+			dprintk("RPC:       Unexpected callback dropped\n");
+			goto error;
+		}
+		if (req == NULL) {
+			/*
+			 * Drop the callback.
+			 * XXX Should we instead terminate the connection?
+ 			 */
+			dprintk("RPC:       Couldn't get rpc_rqst for the callback! Dropping callback...\n");
+			goto error;
+		}
 	}
 
 	rcvbuf = &req->rq_private_buf;
@@ -1026,10 +1047,30 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea
 	}
 
 out:
-	if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))
-		xprt_complete_rqst(req->rq_task, transport->tcp_copied);
+	if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) {
+		if (calldir == RPC_REPLY) {
+			xprt_complete_rqst(req->rq_task, transport->tcp_copied);
+		} else {
+			/*
+ 			 * Add callback request to callback list.  The callback
+ 			 * service sleeps on the sv_cb_waitq waiting for new
+ 			 * requests.  Wake it up after adding enqueing the
+ 			 * request.
+ 			 */
+			spin_lock(&xprt->serv->sv_cb_lock);
+			list_add(&req->rq_list, &xprt->serv->sv_cb_list);
+			spin_unlock(&xprt->serv->sv_cb_lock);
+			wake_up(&xprt->serv->sv_cb_waitq);
+		}
+	}
 	spin_unlock(&xprt->transport_lock);
 	xs_tcp_check_fraghdr(transport);
+	return;
+
+error:
+	transport->tcp_flags &= ~TCP_RCV_COPY_DATA;
+	spin_unlock(&xprt->transport_lock);
+	return;
 }
 
 static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc)
-- 
1.5.2


More information about the pNFS mailing list