packages: nfs-utils/nfs-utils.spec, nfs-utils/svc-create-fixed-port.patch (...

baggins baggins at pld-linux.org
Mon Oct 4 14:02:30 CEST 2010


Author: baggins                      Date: Mon Oct  4 12:02:30 2010 GMT
Module: packages                      Tag: HEAD
---- Log message:
- rel 3
- fix for https://bugzilla.linux-nfs.org/show_bug.cgi?id=190
  (-p <port> option broken in mountd)

---- Files affected:
packages/nfs-utils:
   nfs-utils.spec (1.196 -> 1.197) , svc-create-fixed-port.patch (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: packages/nfs-utils/nfs-utils.spec
diff -u packages/nfs-utils/nfs-utils.spec:1.196 packages/nfs-utils/nfs-utils.spec:1.197
--- packages/nfs-utils/nfs-utils.spec:1.196	Sun Oct  3 20:33:52 2010
+++ packages/nfs-utils/nfs-utils.spec	Mon Oct  4 14:02:22 2010
@@ -14,7 +14,7 @@
 Summary(uk.UTF-8):	Утиліти для NFS та демони підтримки для NFS-сервера ядра
 Name:		nfs-utils
 Version:	1.2.3
-Release:	2
+Release:	3
 License:	GPL v2
 Group:		Networking/Daemons
 Source0:	http://www.kernel.org/pub/linux/utils/nfs/%{name}-%{version}.tar.bz2
@@ -36,6 +36,7 @@
 Patch2:		%{name}-subsys.patch
 Patch3:		%{name}-union-mount.patch
 Patch4:		%{name}-heimdal.patch
+Patch5:		svc-create-fixed-port.patch
 URL:		http://nfs.sourceforge.net/
 BuildRequires:	autoconf >= 2.59
 BuildRequires:	automake
@@ -171,6 +172,7 @@
 %patch2 -p1
 %patch3 -p1
 %patch4 -p1
+%patch5 -p1
 
 %build
 %{__libtoolize}
@@ -414,6 +416,11 @@
 All persons listed below can be reached at <cvs_login>@pld-linux.org
 
 $Log$
+Revision 1.197  2010/10/04 12:02:22  baggins
+- rel 3
+- fix for https://bugzilla.linux-nfs.org/show_bug.cgi?id=190
+  (-p <port> option broken in mountd)
+
 Revision 1.196  2010/10/03 18:33:52  baggins
 - cosmetics
 

================================================================
Index: packages/nfs-utils/svc-create-fixed-port.patch
diff -u /dev/null packages/nfs-utils/svc-create-fixed-port.patch:1.1
--- /dev/null	Mon Oct  4 14:02:30 2010
+++ packages/nfs-utils/svc-create-fixed-port.patch	Mon Oct  4 14:02:22 2010
@@ -0,0 +1,323 @@
+commit 0e94118815e8ff9c1142117764ee3e6cddba0395
+Author: Chuck Lever <chuck.lever at oracle.com>
+Date:   Fri Oct 1 15:04:20 2010 -0400
+
+    libnfs.a: Allow multiple RPC listeners to share listener port number
+    
+    Normally, when "-p" is not specified on the mountd command line, the
+    TI-RPC library chooses random port numbers for each listener.  If a
+    port number _is_ specified on the command line, all the listeners
+    will get the same port number, so SO_REUSEADDR needs to be set on
+    each socket.
+    
+    Thus we can't let TI-RPC create the listener sockets for us in this
+    case; we must create them ourselves and then set SO_REUSEADDR (and
+    other socket options) by hand.
+    
+    Different versions of the same RPC program have to share the same
+    listener and SVCXPRT, so we have to cache xprts we create, and re-use
+    them when additional requests for registration come from the
+    application.
+    
+    Though it doesn't look like it, this fix was "copied" from the legacy
+    rpc_init() function.  It's more complicated for TI-RPC, of course,
+    since you can have an arbitrary number of listeners, not just two
+    (one for AF_INET UDP and one for AF_INET TCP).
+    
+    Fix for:
+    
+      https://bugzilla.linux-nfs.org/show_bug.cgi?id=190
+    
+    There have been no reports of problems with specifying statd's
+    listener port, but I expect this is a problem for statd too.
+    
+    Signed-off-by: Chuck Lever <chuck.lever at oracle.com>
+
+diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
+index 59ba505..fdc4846 100644
+--- a/support/nfs/svc_create.c
++++ b/support/nfs/svc_create.c
+@@ -27,6 +27,7 @@
+ #include <memory.h>
+ #include <signal.h>
+ #include <unistd.h>
++#include <errno.h>
+ #include <netdb.h>
+ 
+ #include <netinet/in.h>
+@@ -41,11 +42,68 @@
+ #include "tcpwrapper.h"
+ #endif
+ 
++#include "sockaddr.h"
+ #include "rpcmisc.h"
+ #include "xlog.h"
+ 
+ #ifdef HAVE_LIBTIRPC
+ 
++#define SVC_CREATE_XPRT_CACHE_SIZE	(8)
++static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, };
++
++/*
++ * Cache an SVC xprt, in case there are more programs or versions to
++ * register against it.
++ */
++static void
++svc_create_cache_xprt(SVCXPRT *xprt)
++{
++	unsigned int i;
++
++	/* Check if we've already got this one... */
++	for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++)
++		if (svc_create_xprt_cache[i] == xprt)
++			return;
++
++	/* No, we don't.  Cache it. */
++	for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++)
++		if (svc_create_xprt_cache[i] == NULL) {
++			svc_create_xprt_cache[i] = xprt;
++			return;
++		}
++
++	xlog(L_ERROR, "%s: Failed to cache an xprt", __func__);
++}
++
++/*
++ * Find a previously cached SVC xprt structure with the given bind address
++ * and transport semantics.
++ *
++ * Returns pointer to a SVC xprt.
++ *
++ * If no matching SVC XPRT can be found, NULL is returned.
++ */
++static SVCXPRT *
++svc_create_find_xprt(const struct sockaddr *bindaddr, const struct netconfig *nconf)
++{
++	unsigned int i;
++
++	for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) {
++		SVCXPRT *xprt = svc_create_xprt_cache[i];
++		struct sockaddr *sap;
++
++		if (xprt == NULL)
++			continue;
++		if (strcmp(nconf->nc_netid, xprt->xp_netid) != 0)
++			continue;
++		sap = (struct sockaddr *)xprt->xp_ltaddr.buf;
++		if (!nfs_compare_sockaddr(bindaddr, sap))
++			continue;
++		return xprt;
++	}
++	return NULL;
++}
++
+ /*
+  * Set up an appropriate bind address, given @port and @nconf.
+  *
+@@ -98,17 +156,112 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port)
+ 	return ai;
+ }
+ 
++/*
++ * Create a listener socket on a specific bindaddr, and set
++ * special socket options to allow it to share the same port
++ * as other listeners.
++ *
++ * Returns an open, bound, and possibly listening network
++ * socket on success.
++ *
++ * Otherwise returns -1 if some error occurs.
++ */
++static int
++svc_create_sock(const struct sockaddr *sap, socklen_t salen,
++		struct netconfig *nconf)
++{
++	int fd, type, protocol;
++	int one = 1;
++
++	switch(nconf->nc_semantics) {
++	case NC_TPI_CLTS:
++		type = SOCK_DGRAM;
++		break;
++	case NC_TPI_COTS_ORD:
++		type = SOCK_STREAM;
++		break;
++	default:
++		xlog(D_GENERAL, "%s: Unrecognized bind address semantics: %u",
++			__func__, nconf->nc_semantics);
++		return -1;
++	}
++
++	if (strcmp(nconf->nc_proto, NC_UDP) == 0)
++		protocol = (int)IPPROTO_UDP;
++	else if (strcmp(nconf->nc_proto, NC_TCP) == 0)
++		protocol = (int)IPPROTO_TCP;
++	else {
++		xlog(D_GENERAL, "%s: Unrecognized bind address protocol: %s",
++			__func__, nconf->nc_proto);
++		return -1;
++	}
++
++	fd = socket((int)sap->sa_family, type, protocol);
++	if (fd == -1) {
++		xlog(L_ERROR, "Could not make a socket: (%d) %m",
++			errno);
++		return -1;
++	}
++
++#ifdef IPV6_SUPPORTED
++	if (sap->sa_family == AF_INET6) {
++		if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
++				&one, sizeof(one)) == -1) {
++			xlog(L_ERROR, "Failed to set IPV6_V6ONLY: (%d) %m",
++				errno);
++			(void)close(fd);
++			return -1;
++		}
++	}
++#endif	/* IPV6_SUPPORTED */
++
++	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
++		       &one, sizeof(one)) == -1) {
++		xlog(L_ERROR, "Failed to set SO_REUSEADDR: (%d) %m",
++			errno);
++		(void)close(fd);
++		return -1;
++	}
++
++	if (bind(fd, sap, salen) == -1) {
++		xlog(L_ERROR, "Could not bind socket: (%d) %m",
++			errno);
++		(void)close(fd);
++		return -1;
++	}
++
++	if (nconf->nc_semantics == NC_TPI_COTS_ORD)
++		if (listen(fd, SOMAXCONN) == -1) {
++			xlog(L_ERROR, "Could not listen on socket: (%d) %m",
++				errno);
++			(void)close(fd);
++			return -1;
++		}
++
++	return fd;
++}
++
++/*
++ * The simple case is allowing the TI-RPC library to create a
++ * transport itself, given just the bind address and transport
++ * semantics.
++ *
++ * The port is chosen at random by the library; we don't know
++ * what it is.  So the new xprt cannot be cached here.
++ *
++ * Returns the count of started listeners (one or zero).
++ */
+ static unsigned int
+-svc_create_nconf(const char *name, const rpcprog_t program,
++svc_create_nconf_rand_port(const char *name, const rpcprog_t program,
+ 		const rpcvers_t version,
+ 		void (*dispatch)(struct svc_req *, SVCXPRT *),
+-		const uint16_t port, struct netconfig *nconf)
++		struct netconfig *nconf)
+ {
+ 	struct t_bind bindaddr;
+ 	struct addrinfo *ai;
+ 	SVCXPRT	*xprt;
+ 
+-	ai = svc_create_bindaddr(nconf, port);
++	ai = svc_create_bindaddr(nconf, 0);
+ 	if (ai == NULL)
+ 		return 0;
+ 
+@@ -119,7 +272,7 @@ svc_create_nconf(const char *name, const rpcprog_t program,
+ 	freeaddrinfo(ai);
+ 	if (xprt == NULL) {
+ 		xlog(D_GENERAL, "Failed to create listener xprt "
+-				"(%s, %u, %s)", name, version, nconf->nc_netid);
++			"(%s, %u, %s)", name, version, nconf->nc_netid);
+ 		return 0;
+ 	}
+ 
+@@ -133,6 +286,81 @@ svc_create_nconf(const char *name, const rpcprog_t program,
+ 	return 1;
+ }
+ 
++/*
++ * If a port is specified on the command line, that port value will be
++ * the same for all listeners created here.  Create each listener socket
++ * in advance and set SO_REUSEADDR, rather than allowing the RPC library
++ * to create the listeners for us on a randomly chosen port (RPC_ANYFD).
++ *
++ * Also, to support multiple RPC versions on the same listener, register
++ * any new versions on the same transport that is already handling other
++ * versions on the same bindaddr and transport.  To accomplish this,
++ * cache previously created xprts on a list, and check that list before
++ * creating a new socket for this [program, version].
++ *
++ * Returns the count of started listeners (one or zero).
++ */
++static unsigned int
++svc_create_nconf_fixed_port(const char *name, const rpcprog_t program,
++		const rpcvers_t version,
++		void (*dispatch)(struct svc_req *, SVCXPRT *),
++		const uint16_t port, struct netconfig *nconf)
++{
++	struct addrinfo *ai;
++	SVCXPRT	*xprt;
++
++	ai = svc_create_bindaddr(nconf, port);
++	if (ai == NULL)
++		return 0;
++
++	xprt = svc_create_find_xprt(ai->ai_addr, nconf);
++	if (xprt == NULL) {
++		int fd;
++
++		fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf);
++		if (fd == -1)
++			goto out_free;
++
++		xprt = svc_tli_create(fd, nconf, NULL, 0, 0);
++		if (xprt == NULL) {
++			xlog(D_GENERAL, "Failed to create listener xprt "
++				"(%s, %u, %s)", name, version, nconf->nc_netid);
++			(void)close(fd);
++			goto out_free;
++		}
++	}
++
++	if (!svc_reg(xprt, program, version, dispatch, nconf)) {
++		/* svc_reg(3) destroys @xprt in this case */
++		xlog(D_GENERAL, "Failed to register (%s, %u, %s)",
++				name, version, nconf->nc_netid);
++		goto out_free;
++	}
++
++	svc_create_cache_xprt(xprt);
++
++	freeaddrinfo(ai);
++	return 1;
++
++out_free:
++	freeaddrinfo(ai);
++	return 0;
++}
++
++static unsigned int
++svc_create_nconf(const char *name, const rpcprog_t program,
++		const rpcvers_t version,
++		void (*dispatch)(struct svc_req *, SVCXPRT *),
++		const uint16_t port, struct netconfig *nconf)
++{
++	if (port != 0)
++		return svc_create_nconf_fixed_port(name, program,
++			version, dispatch, port, nconf);
++
++	return svc_create_nconf_rand_port(name, program,
++			version, dispatch, nconf);
++}
++
+ /**
+  * nfs_svc_create - start up RPC svc listeners
+  * @name: C string containing name of new service
================================================================

---- CVS-web:
    http://cvs.pld-linux.org/cgi-bin/cvsweb.cgi/packages/nfs-utils/nfs-utils.spec?r1=1.196&r2=1.197&f=u



More information about the pld-cvs-commit mailing list