[ofa-general] [RFC,PATCH 16/20] svc: xpt_create_svc

Tom Tucker tom at opengridcomputing.com
Mon Aug 20 11:58:01 PDT 2007


Add transport function that makes the creation of a listening endpoint 
transport independent.

Signed-off-by: Tom Tucker <tom at opengridcomputing.com>
---

 include/linux/sunrpc/svcsock.h |    5 +++
 net/sunrpc/svcsock.c           |   65 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index cc911ab..e2d0256 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -14,6 +14,10 @@ #include <linux/sunrpc/svc.h>
 struct svc_xprt {
 	const char		*xpt_name;
 	struct module		*xpt_owner;
+	/* Create an svc socket for this transport */
+	int			(*xpt_create_svc)(struct svc_serv *,
+						  struct sockaddr *,
+						  int);
 	int			(*xpt_recvfrom)(struct svc_rqst *rqstp);
 	int			(*xpt_sendto)(struct svc_rqst *rqstp);
 	/*
@@ -109,6 +113,7 @@ #define	SK_LISTENER	11			/* listener (e.
 int 		svc_register_transport(struct svc_xprt *xprt);
 int 		svc_unregister_transport(struct svc_xprt *xprt);
 int		svc_makesock(struct svc_serv *, int, unsigned short, int flags);
+int		svc_create_svcsock(struct svc_serv *, char *, unsigned short, int);
 void		svc_force_close_socket(struct svc_sock *);
 int		svc_recv(struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 276737e..44d6484 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -87,6 +87,8 @@ static void		svc_close_socket(struct svc
 static void		svc_sock_detach(struct svc_sock *);
 static void		svc_sock_free(struct svc_sock *);
 
+static int
+svc_create_socket(struct svc_serv *, int, struct sockaddr *, int, int);
 static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
 static int svc_deferred_recv(struct svc_rqst *rqstp);
 static struct cache_deferred_req *svc_defer(struct cache_req *req);
@@ -434,6 +436,7 @@ __svc_sock_put(struct svc_sock *svsk)
 
 	if (svsk->sk_info_authunix != NULL)
 		svcauth_unix_info_release(svsk->sk_info_authunix);
+	module_put(svsk->sk_xprt->xpt_owner);
 	svsk->sk_xprt->xpt_free(svsk);
 }
 EXPORT_SYMBOL_GPL(__svc_sock_put);
@@ -961,9 +964,17 @@ svc_udp_has_wspace(struct svc_sock *svsk
 	return svc_sock_has_write_space(svsk, sock_wspace(svsk->sk_sk));
 }
 
+static int
+svc_udp_create_svc(struct svc_serv *serv, struct sockaddr *sa, int flags)
+{
+	return svc_create_socket(serv, IPPROTO_UDP, sa,
+				 sizeof(struct sockaddr_in), flags);
+}
+
 static struct svc_xprt svc_udp_xprt = {
 	.xpt_name = "udp",
 	.xpt_owner = THIS_MODULE,
+	.xpt_create_svc = svc_udp_create_svc,
 	.xpt_recvfrom = svc_udp_recvfrom,
 	.xpt_sendto = svc_udp_sendto,
 	.xpt_detach = svc_sock_detach,
@@ -1421,9 +1432,17 @@ svc_tcp_has_wspace(struct svc_sock *svsk
 	return svc_sock_has_write_space(svsk, sk_stream_wspace(svsk->sk_sk));
 }
 
+static int
+svc_tcp_create_svc(struct svc_serv *serv, struct sockaddr *sa, int flags)
+{
+	return svc_create_socket(serv, IPPROTO_TCP, sa,
+				 sizeof(struct sockaddr_in), flags);
+}
+
 static struct svc_xprt svc_tcp_xprt = {
 	.xpt_name = "tcp",
 	.xpt_owner = THIS_MODULE,
+	.xpt_create_svc = svc_tcp_create_svc,
 	.xpt_recvfrom = svc_tcp_recvfrom,
 	.xpt_sendto = svc_tcp_sendto,
 	.xpt_detach = svc_sock_detach,
@@ -1606,6 +1625,7 @@ svc_recv(struct svc_rqst *rqstp, long ti
 		svc_delete_socket(svsk);
 	} else if (test_bit(SK_LISTENER, &svsk->sk_flags)) {
 		svsk->sk_xprt->xpt_accept(svsk);
+		__module_get(svsk->sk_xprt->xpt_owner);
 		svc_sock_received(svsk);
 	} else {
 		dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n",
@@ -1885,7 +1905,7 @@ EXPORT_SYMBOL_GPL(svc_addsock);
  * Create socket for RPC service.
  */
 static int svc_create_socket(struct svc_serv *serv, int protocol,
-				struct sockaddr *sin, int len, int flags)
+			     struct sockaddr *sin, int len, int flags)
 {
 	struct svc_sock	*svsk;
 	struct socket	*sock;
@@ -2037,18 +2057,53 @@ void svc_force_close_socket(struct svc_s
  *
  */
 int svc_makesock(struct svc_serv *serv, int protocol, unsigned short port,
-			int flags)
+		 int flags)
 {
+	dprintk("svc: creating socket proto = %d\n", protocol);
+	switch (protocol) {
+	case IPPROTO_TCP:
+		return svc_create_svcsock(serv, "tcp", port, flags);
+	case IPPROTO_UDP:
+		return svc_create_svcsock(serv, "udp", port, flags);
+	default:
+		return -EINVAL;
+	}
+}
+
+int svc_create_svcsock(struct svc_serv *serv, char *transport, unsigned short port,
+		       int flags)
+{
+	int ret = -ENOENT;
+	struct list_head *le;
 	struct sockaddr_in sin = {
 		.sin_family		= AF_INET,
 		.sin_addr.s_addr	= INADDR_ANY,
 		.sin_port		= htons(port),
 	};
+	dprintk("svc: creating transport socket %s[%d]\n", transport, port);
+	spin_lock(&svc_transport_lock);
+	list_for_each(le, &svc_transport_list) {
+		struct svc_xprt *xprt =
+			list_entry(le, struct svc_xprt, xpt_list);
 
-	dprintk("svc: creating socket proto = %d\n", protocol);
-	return svc_create_socket(serv, protocol, (struct sockaddr *) &sin,
-							sizeof(sin), flags);
+		if (strcmp(transport, xprt->xpt_name)==0) {
+			spin_unlock(&svc_transport_lock);
+			if (try_module_get(xprt->xpt_owner)) {
+				ret = xprt->xpt_create_svc(serv,
+							   (struct sockaddr*)&sin,
+							   flags);
+				if (ret < 0)
+					module_put(xprt->xpt_owner);
+				goto out;
+			}
+		}
+	}
+	spin_unlock(&svc_transport_lock);
+	dprintk("svc: transport %s not found\n", transport);
+ out:
+	return ret;
 }
+EXPORT_SYMBOL_GPL(svc_create_svcsock);
 
 /*
  * Handle defer and revisit of requests



More information about the general mailing list