summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-06-10 00:15:46 +0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-11 07:40:34 +0400
commitfc1b356f566fe05929ec2a88ce2c7b15f8b6279f (patch)
tree7d790ea2d3618b9cb166081a86797411f3547e44
parent07a2bf1da4765d987ffd1d8045e92ba032e0ad78 (diff)
downloadlinux-fc1b356f566fe05929ec2a88ce2c7b15f8b6279f.tar.xz
SUNRPC: Fix races in rpcauth_create
See the FIXME: auth_flavors[] really needs a lock and module refcounting. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--net/sunrpc/auth.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index f6b6c81cbc3e..584f24311a80 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -18,6 +18,7 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
+static DEFINE_SPINLOCK(rpc_authflavor_lock);
static struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = {
&authnull_ops, /* AUTH_NULL */
&authunix_ops, /* AUTH_UNIX */
@@ -35,26 +36,34 @@ int
rpcauth_register(struct rpc_authops *ops)
{
rpc_authflavor_t flavor;
+ int ret = -EPERM;
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
return -EINVAL;
- if (auth_flavors[flavor] != NULL)
- return -EPERM; /* what else? */
- auth_flavors[flavor] = ops;
- return 0;
+ spin_lock(&rpc_authflavor_lock);
+ if (auth_flavors[flavor] == NULL) {
+ auth_flavors[flavor] = ops;
+ ret = 0;
+ }
+ spin_unlock(&rpc_authflavor_lock);
+ return ret;
}
int
rpcauth_unregister(struct rpc_authops *ops)
{
rpc_authflavor_t flavor;
+ int ret = -EPERM;
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
return -EINVAL;
- if (auth_flavors[flavor] != ops)
- return -EPERM; /* what else? */
- auth_flavors[flavor] = NULL;
- return 0;
+ spin_lock(&rpc_authflavor_lock);
+ if (auth_flavors[flavor] == ops) {
+ auth_flavors[flavor] = NULL;
+ ret = 0;
+ }
+ spin_unlock(&rpc_authflavor_lock);
+ return ret;
}
struct rpc_auth *
@@ -68,15 +77,19 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
if (flavor >= RPC_AUTH_MAXFLAVOR)
goto out;
- /* FIXME - auth_flavors[] really needs an rw lock,
- * and module refcounting. */
#ifdef CONFIG_KMOD
if ((ops = auth_flavors[flavor]) == NULL)
request_module("rpc-auth-%u", flavor);
#endif
- if ((ops = auth_flavors[flavor]) == NULL)
+ spin_lock(&rpc_authflavor_lock);
+ ops = auth_flavors[flavor];
+ if (ops == NULL || !try_module_get(ops->owner)) {
+ spin_unlock(&rpc_authflavor_lock);
goto out;
+ }
+ spin_unlock(&rpc_authflavor_lock);
auth = ops->create(clnt, pseudoflavor);
+ module_put(ops->owner);
if (IS_ERR(auth))
return auth;
if (clnt->cl_auth)