summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2014-01-04 13:18:05 +0100
committerJ. Bruce Fields <bfields@redhat.com>2014-01-06 21:14:18 +0100
commit0fdc26785d0a5bb33d9adb572307fd2d7a406734 (patch)
tree85474a5723bbf22117c654f357aaa26e9999fdce
parentsunrpc: fix potential race between setting use_gss_proxy and the upcall rpc_clnt (diff)
downloadlinux-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.c42
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)
{