[PATCH 4/6] SUNRPC: Simplify kernel RPC service registration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The kernel registers RPC services with the local portmapper with an
rpcbind SET upcall to the local portmapper.  Traditionally, this used
rpcbind v2, but registering RPC services that support IPv6 requires
rpcbind v3 or v4.

Previously the kernel used the registration upcall to detect whether
user space supported IPv6 for RPC at all, and fail the service
creation if it didn't.  This is probably unnecessary paranoia.

Since the kernel uses a single listener (either AF_INET or AF_INET6)
to handle all requests for a particular RPC service, AF_INET6
listeners handle IPv4 RPC requests too.  If user space doesn't allow
an AF_INET6 kernel service to be registered, that should be no
trouble at all for the kernel's AF_INET6 RPC listener -- it just won't
get any RPC requests via IPv6.  So we don't need to register the
service for IPv6 if user space doesn't allow it.

So, we try registration via rpcbind v4 first; if that fails, we retry
with rpcbind v2, and support only IPv4 requests.

This provides complete backwards compatibilty with legacy user space
that only supports rpcbind v2.  The only down-side is that registering
a new kernel RPC service may take an extra exchange with the local
portmapper, but this is an infrequent operation, so it shouldn't
matter.

This patch is part of a series that addresses
   http://bugzilla.kernel.org/show_bug.cgi?id=12256

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---

 net/sunrpc/svc.c |   50 ++++++++++++++++++++++++--------------------------
 1 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 8dc4a1e..3cf1b3c 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -719,8 +719,6 @@ svc_exit_thread(struct svc_rqst *rqstp)
 }
 EXPORT_SYMBOL_GPL(svc_exit_thread);
 
-#ifdef CONFIG_SUNRPC_REGISTER_V4
-
 /*
  * Register an "inet" protocol family netid with the local
  * rpcbind daemon via an rpcbind v4 SET request.
@@ -741,6 +739,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
 		.sin_port		= htons(port),
 	};
 	char *netid;
+	int error;
 
 	switch (protocol) {
 	case IPPROTO_UDP:
@@ -753,8 +752,17 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
 		return -ENOPROTOOPT;
 	}
 
-	return rpcb_v4_register(program, version,
-				(struct sockaddr *)&sin, netid);
+	error = rpcb_v4_register(program, version,
+					(struct sockaddr *)&sin, netid);
+
+	/*
+	 * User space didn't support rpcbind v4, so retry this
+	 * registration request with the legacy rpcbind v2 protocol.
+	 */
+	if (error == -EPROTONOSUPPORT)
+		error = rpcb_register(program, version, protocol, port);
+
+	return error;
 }
 
 /*
@@ -777,6 +785,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
 		.sin6_port		= htons(port),
 	};
 	char *netid;
+	int error;
 
 	switch (protocol) {
 	case IPPROTO_UDP:
@@ -789,8 +798,18 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
 		return -ENOPROTOOPT;
 	}
 
-	return rpcb_v4_register(program, version,
+	error = rpcb_v4_register(program, version,
 				(struct sockaddr *)&sin6, netid);
+
+	/*
+	 * User space didn't support registering an IPv6 service,
+	 * so register this service for IPv4 only, using the legacy
+	 * rpcbind v2 protocol.
+	 */
+	if (error == -EPROTONOSUPPORT)
+		error = rpcb_register(program, version, protocol, port);
+
+	return error;
 }
 
 /*
@@ -831,27 +850,6 @@ static int __svc_register(const u32 program, const u32 version,
 	return -EAFNOSUPPORT;
 }
 
-#else	/* CONFIG_SUNRPC_REGISTER_V4 */
-
-/*
- * Register a kernel RPC service via rpcbind version 2.
- *
- * Returns zero on success; a negative errno value is returned
- * if any error occurs.
- */
-static int __svc_register(const u32 program, const u32 version,
-			  sa_family_t family,
-			  const unsigned short protocol,
-			  const unsigned short port)
-{
-	if (family != AF_INET)
-		return -EAFNOSUPPORT;
-
-	return rpcb_register(program, version, protocol, port);
-}
-
-#endif /* CONFIG_SUNRPC_REGISTER_V4 */
-
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux