aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2009-03-18 20:47:36 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-03-28 15:58:37 -0400
commitcadc0fa534e51e20fdffe1623913c163a18d71b1 (patch)
tree51d41748b7c98eab0749d033b174b0584e25088a
parentd5a8620f7c8a5bcade730e2fa1224191f289fb00 (diff)
SUNRPC: Simplify kernel RPC service registration
The kernel registers RPC services with the local portmapper with an rpcbind SET upcall to the local portmapper. Traditionally, this used rpcbind v2 (PMAP), but registering RPC services that support IPv6 requires rpcbind v3 or v4. Since we now want separate PF_INET and PF_INET6 listeners for each kernel RPC service, svc_register() will do only one of those registrations at a time. For PF_INET, it tries an rpcb v4 SET upcall first; if that fails, it does a legacy portmap SET. This makes it entirely backwards compatible with legacy user space, but allows a proper v4 SET to be used if rpcbind is available. For PF_INET6, it does an rpcb v4 SET upcall. If that fails, it fails the registration, and thus the transport creation. This let's the kernel detect if user space is able to support IPv6 RPC services, and thus whether it should maintain a PF_INET6 listener for each service at all. 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 on legacy systems, but this is an infrequent operation and is done over UDP (no lingering sockets in TIMEWAIT), so it shouldn't be consequential. 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@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--net/sunrpc/svc.c79
1 files changed, 34 insertions, 45 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index bd0ee312dac9..142f64745fba 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -718,8 +718,6 @@ svc_exit_thread(struct svc_rqst *rqstp)
718} 718}
719EXPORT_SYMBOL_GPL(svc_exit_thread); 719EXPORT_SYMBOL_GPL(svc_exit_thread);
720 720
721#ifdef CONFIG_SUNRPC_REGISTER_V4
722
723/* 721/*
724 * Register an "inet" protocol family netid with the local 722 * Register an "inet" protocol family netid with the local
725 * rpcbind daemon via an rpcbind v4 SET request. 723 * rpcbind daemon via an rpcbind v4 SET request.
@@ -734,12 +732,13 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
734 const unsigned short protocol, 732 const unsigned short protocol,
735 const unsigned short port) 733 const unsigned short port)
736{ 734{
737 struct sockaddr_in sin = { 735 const struct sockaddr_in sin = {
738 .sin_family = AF_INET, 736 .sin_family = AF_INET,
739 .sin_addr.s_addr = htonl(INADDR_ANY), 737 .sin_addr.s_addr = htonl(INADDR_ANY),
740 .sin_port = htons(port), 738 .sin_port = htons(port),
741 }; 739 };
742 char *netid; 740 const char *netid;
741 int error;
743 742
744 switch (protocol) { 743 switch (protocol) {
745 case IPPROTO_UDP: 744 case IPPROTO_UDP:
@@ -752,10 +751,20 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
752 return -ENOPROTOOPT; 751 return -ENOPROTOOPT;
753 } 752 }
754 753
755 return rpcb_v4_register(program, version, 754 error = rpcb_v4_register(program, version,
756 (struct sockaddr *)&sin, netid); 755 (const struct sockaddr *)&sin, netid);
756
757 /*
758 * User space didn't support rpcbind v4, so retry this
759 * registration request with the legacy rpcbind v2 protocol.
760 */
761 if (error == -EPROTONOSUPPORT)
762 error = rpcb_register(program, version, protocol, port);
763
764 return error;
757} 765}
758 766
767#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
759/* 768/*
760 * Register an "inet6" protocol family netid with the local 769 * Register an "inet6" protocol family netid with the local
761 * rpcbind daemon via an rpcbind v4 SET request. 770 * rpcbind daemon via an rpcbind v4 SET request.
@@ -770,12 +779,13 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
770 const unsigned short protocol, 779 const unsigned short protocol,
771 const unsigned short port) 780 const unsigned short port)
772{ 781{
773 struct sockaddr_in6 sin6 = { 782 const struct sockaddr_in6 sin6 = {
774 .sin6_family = AF_INET6, 783 .sin6_family = AF_INET6,
775 .sin6_addr = IN6ADDR_ANY_INIT, 784 .sin6_addr = IN6ADDR_ANY_INIT,
776 .sin6_port = htons(port), 785 .sin6_port = htons(port),
777 }; 786 };
778 char *netid; 787 const char *netid;
788 int error;
779 789
780 switch (protocol) { 790 switch (protocol) {
781 case IPPROTO_UDP: 791 case IPPROTO_UDP:
@@ -788,9 +798,19 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
788 return -ENOPROTOOPT; 798 return -ENOPROTOOPT;
789 } 799 }
790 800
791 return rpcb_v4_register(program, version, 801 error = rpcb_v4_register(program, version,
792 (struct sockaddr *)&sin6, netid); 802 (const struct sockaddr *)&sin6, netid);
803
804 /*
805 * User space didn't support rpcbind version 4, so we won't
806 * use a PF_INET6 listener.
807 */
808 if (error == -EPROTONOSUPPORT)
809 error = -EAFNOSUPPORT;
810
811 return error;
793} 812}
813#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
794 814
795/* 815/*
796 * Register a kernel RPC service via rpcbind version 4. 816 * Register a kernel RPC service via rpcbind version 4.
@@ -809,48 +829,17 @@ static int __svc_register(const u32 program, const u32 version,
809 case PF_INET: 829 case PF_INET:
810 return __svc_rpcb_register4(program, version, 830 return __svc_rpcb_register4(program, version,
811 protocol, port); 831 protocol, port);
832 break;
833#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
812 case PF_INET6: 834 case PF_INET6:
813 error = __svc_rpcb_register6(program, version, 835 return__svc_rpcb_register6(program, version,
814 protocol, port); 836 protocol, port);
815 if (error < 0) 837#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
816 return error;
817
818 /*
819 * Work around bug in some versions of Linux rpcbind
820 * which don't allow registration of both inet and
821 * inet6 netids.
822 *
823 * Error return ignored for now.
824 */
825 __svc_rpcb_register4(program, version,
826 protocol, port);
827 return 0;
828 } 838 }
829 839
830 return -EAFNOSUPPORT; 840 return -EAFNOSUPPORT;
831} 841}
832 842
833#else /* CONFIG_SUNRPC_REGISTER_V4 */
834
835/*
836 * Register a kernel RPC service via rpcbind version 2.
837 *
838 * Returns zero on success; a negative errno value is returned
839 * if any error occurs.
840 */
841static int __svc_register(const u32 program, const u32 version,
842 const int family,
843 const unsigned short protocol,
844 const unsigned short port)
845{
846 if (family != PF_INET)
847 return -EAFNOSUPPORT;
848
849 return rpcb_register(program, version, protocol, port);
850}
851
852#endif /* CONFIG_SUNRPC_REGISTER_V4 */
853
854/** 843/**
855 * svc_register - register an RPC service with the local portmapper 844 * svc_register - register an RPC service with the local portmapper
856 * @serv: svc_serv struct for the service to register 845 * @serv: svc_serv struct for the service to register