From 927aa10019e5e65fc320fe0302cdf703e57b0025 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20R=C4=99korajski?= Date: Mon, 4 Oct 2010 12:02:22 +0000 Subject: [PATCH] - rel 3 - fix for https://bugzilla.linux-nfs.org/show_bug.cgi?id=190 (-p option broken in mountd) Changed files: nfs-utils.spec -> 1.197 svc-create-fixed-port.patch -> 1.1 --- nfs-utils.spec | 4 +- svc-create-fixed-port.patch | 323 ++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 svc-create-fixed-port.patch diff --git a/nfs-utils.spec b/nfs-utils.spec index 5e99b09..f6e6539 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -13,7 +13,7 @@ Summary(ru.UTF-8): Утилиты для NFS и демоны поддержки 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 @@ -35,6 +35,7 @@ Patch1: %{name}-statdpath.patch 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 @@ -170,6 +171,7 @@ Wspólne programy do obsługi NFS. %patch2 -p1 %patch3 -p1 %patch4 -p1 +%patch5 -p1 %build %{__libtoolize} diff --git a/svc-create-fixed-port.patch b/svc-create-fixed-port.patch new file mode 100644 index 0000000..2c197e5 --- /dev/null +++ b/svc-create-fixed-port.patch @@ -0,0 +1,323 @@ +commit 0e94118815e8ff9c1142117764ee3e6cddba0395 +Author: Chuck Lever +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 + +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 + #include + #include ++#include + #include + + #include +@@ -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 -- 2.44.0