Browse Source

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>
Jeff Layton 11 years ago
parent
commit
0fdc26785d
1 changed files with 18 additions and 24 deletions
  1. 18 24
      net/sunrpc/auth_gss/svcauth_gss.c

+ 18 - 24
net/sunrpc/auth_gss/svcauth_gss.c

@@ -1263,41 +1263,35 @@ out:
 	return ret;
 	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);
 	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;
 	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);
 	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,
 static ssize_t write_gssp(struct file *file, const char __user *buf,
 			 size_t count, loff_t *ppos)
 			 size_t count, loff_t *ppos)
 {
 {