In the current rawhide kernels, when a NFS mount is done, and then an unmount and then another NFS mount, the second mount will fail with: mount.nfs: access denied by server while mounting <server>:<export>
The problem is the kernel lockd thread, which is started on the first NFS mount and stopped on the last NFS mount, was failing to start up again on the second mount.
The failure was caused by lockd doing IPV6 service registrations on the way up and then failing to unregister those services on the way down. The next time lockd tried to register those services, rpcbind failed them since they already existed...
These two patches fixes this problem.
Note: These patches will be in upstream very shortly....
steved.
The user space TI-RPC library uses an empty string for the universal address when unregistering all target addresses for [program, version]. Allow the kernel's rpcb client to support the same.
Here, we are switching between several registration methods based on the protocol family of the incoming address. Rename the other rpcbind v4 registration functions to make it clear that they are switched on protocol family as well. In /etc/netconfig, this is either "inet" or "inet6". The loopback protocol families are not supported in the kernel.
Signed-off-by: Chuck Lever chuck.lever@oracle.com Signed-off-by: Steve Dickson steved@redhat.com ---
net/sunrpc/rpcb_clnt.c | 38 ++++++++++++++++++++++++++++---------- 1 files changed, 28 insertions(+), 10 deletions(-)
diff -up linux-2.6.28.x86_64/net/sunrpc/rpcb_clnt.c.orig linux-2.6.28.x86_64/net/sunrpc/rpcb_clnt.c --- linux-2.6.28.x86_64/net/sunrpc/rpcb_clnt.c.orig 2009-02-10 13:14:34.000000000 -0500 +++ linux-2.6.28.x86_64/net/sunrpc/rpcb_clnt.c 2009-02-11 14:50:47.000000000 -0500 @@ -255,8 +255,8 @@ int rpcb_register(u32 prog, u32 vers, in /* * Fill in AF_INET family-specific arguments to register */ -static int rpcb_register_netid4(struct sockaddr_in *address_to_register, - struct rpc_message *msg) +static int rpcb_register_inet4(struct sockaddr_in *address_to_register, + struct rpc_message *msg) { struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(address_to_register->sin_port); @@ -283,8 +283,8 @@ static int rpcb_register_netid4(struct s /* * Fill in AF_INET6 family-specific arguments to register */ -static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, - struct rpc_message *msg) +static int rpcb_register_inet6(struct sockaddr_in6 *address_to_register, + struct rpc_message *msg) { struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(address_to_register->sin6_port); @@ -312,6 +312,20 @@ static int rpcb_register_netid6(struct s return rpcb_register_call(RPCBVERS_4, msg); }
+static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) +{ + struct rpcbind_args *map = msg->rpc_argp; + + dprintk("RPC: unregistering [%u, %u, '%s'] with " + "local rpcbind\n", + map->r_prog, map->r_vers, map->r_netid); + + map->r_addr = ""; + msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; + + return rpcb_register_call(RPCBVERS_4, msg); +} + /** * rpcb_v4_register - set or unset a port registration with the local rpcbind * @program: RPC program number of service to (un)register @@ -329,10 +343,11 @@ static int rpcb_register_netid6(struct s * invoke this function once for each [program, version, address, * netid] tuple they wish to advertise. * - * Callers may also unregister RPC services that are no longer - * available by setting the port number in the passed-in address - * to zero. Callers pass a netid of "" to unregister all - * transport netids associated with [program, version, address]. + * Callers may also unregister RPC services that are registered at a + * specific address by setting the port number in @address to zero. + * They may unregister all registered protocol families at once for + * a service by passing a NULL @address argument. If @netid is "" + * then all netids for [program, version, address] are unregistered. * * This function uses rpcbind protocol version 4 to contact the * local rpcbind daemon. The local rpcbind daemon must support @@ -367,12 +382,15 @@ int rpcb_v4_register(const u32 program, .rpc_argp = &map, };
+ if (address == NULL) + return rpcb_unregister_all_protofamilies(&msg); + switch (address->sa_family) { case AF_INET: - return rpcb_register_netid4((struct sockaddr_in *)address, + return rpcb_register_inet4((struct sockaddr_in *)address, &msg); case AF_INET6: - return rpcb_register_netid6((struct sockaddr_in6 *)address, + return rpcb_register_inet6((struct sockaddr_in6 *)address, &msg); }
We now have some evidence that PMAP_UNSET clears only "inet" entries, and not "inet6" entries, in the rpcbind database. The svc_unregister() function also must work if user space doesn't support rpcbind version 4 at all.
Thus we'll send an rpcbind v4 UNSET, and if that fails, we'll send a PMAP_UNSET.
This simplifies the code in svc_unregister() and provides better backwards compatibility with legacy user space that does not support rpcbind version 4.
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: Steve Dickson steved@redhat.com ---
net/sunrpc/svc.c | 35 ++++++++++++++--------------------- 1 files changed, 14 insertions(+), 21 deletions(-)
diff -up linux-2.6.28.x86_64/net/sunrpc/svc.c.orig linux-2.6.28.x86_64/net/sunrpc/svc.c --- linux-2.6.28.x86_64/net/sunrpc/svc.c.orig 2009-02-10 13:14:34.000000000 -0500 +++ linux-2.6.28.x86_64/net/sunrpc/svc.c 2009-02-11 15:02:14.000000000 -0500 @@ -903,15 +903,25 @@ int svc_register(const struct svc_serv * }
/* - * Olaf says a v2 UNSET should clear _all_ entries, including any - * registered via a v4 SET + * If user space is running rpcbind, it should take the v4 UNSET + * and clear everything for this [program, version]. If user space + * is running portmap, it will reject the v4 UNSET, but won't have + * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient + * in this case to clear all existing entries for [program, version]. */ static void __svc_unregister(const u32 program, const u32 version, const char *progname) { int error;
- error = rpcb_register(program, version, 0, 0); + /* + * User space didn't support rpcbind v4, so retry this + * request with the legacy rpcbind v2 protocol. + */ + error = rpcb_v4_register(program, version, NULL, ""); + if (error == -EPROTONOSUPPORT) + error = rpcb_register(program, version, 0, 0); + dprintk("svc: %s(%sv%u), error %d\n", __func__, progname, version, error); }
kernel@lists.fedoraproject.org