diff options
author | Jeff Layton <jlayton@redhat.com> | 2014-01-04 13:18:05 +0100 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-01-06 21:14:18 +0100 |
commit | 0fdc26785d0a5bb33d9adb572307fd2d7a406734 (patch) | |
tree | 85474a5723bbf22117c654f357aaa26e9999fdce | |
parent | sunrpc: fix potential race between setting use_gss_proxy and the upcall rpc_clnt (diff) | |
download | linux-0fdc26785d0a5bb33d9adb572307fd2d7a406734.tar.xz linux-0fdc26785d0a5bb33d9adb572307fd2d7a406734.zip |
sunrpc: get rid of use_gssp_lock
We can achieve the same result with a cmpxchg(). This also fixes a
potential race in use_gss_proxy(). The value of sn->use_gss_proxy could
go from -1 to 1 just after we check it in use_gss_proxy() but before we
acquire the spinlock. The procfile write would end up returning success
but the value would flip to 0 soon afterward. With this method we not
only avoid locking but the first "setter" always wins.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 42 |
1 files changed, 18 insertions, 24 deletions
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 60dc3700b2cb..2a935404047f 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1263,41 +1263,35 @@ out: return ret; } -DEFINE_SPINLOCK(use_gssp_lock); - -static bool use_gss_proxy(struct net *net) +/* + * Try to set the sn->use_gss_proxy variable to a new value. We only allow + * it to be changed if it's currently undefined (-1). If it's any other value + * then return -EBUSY unless the type wouldn't have changed anyway. + */ +static int set_gss_proxy(struct net *net, int type) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + int ret; - if (sn->use_gss_proxy != -1) - return sn->use_gss_proxy; - spin_lock(&use_gssp_lock); - /* - * If you wanted gss-proxy, you should have said so before - * starting to accept requests: - */ - sn->use_gss_proxy = 0; - spin_unlock(&use_gssp_lock); + WARN_ON_ONCE(type != 0 && type != 1); + ret = cmpxchg(&sn->use_gss_proxy, -1, type); + if (ret != -1 && ret != type) + return -EBUSY; return 0; } -#ifdef CONFIG_PROC_FS - -static int set_gss_proxy(struct net *net, int type) +static bool use_gss_proxy(struct net *net) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); - int ret = 0; - WARN_ON_ONCE(type != 0 && type != 1); - spin_lock(&use_gssp_lock); - if (sn->use_gss_proxy == -1 || sn->use_gss_proxy == type) - sn->use_gss_proxy = type; - else - ret = -EBUSY; - spin_unlock(&use_gssp_lock); - return ret; + /* If use_gss_proxy is still undefined, then try to disable it */ + if (sn->use_gss_proxy == -1) + set_gss_proxy(net, 0); + return sn->use_gss_proxy; } +#ifdef CONFIG_PROC_FS + static ssize_t write_gssp(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { |