diff options
author | Jeff Layton <jlayton@redhat.com> | 2014-01-04 07:18:05 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-01-06 15:14:18 -0500 |
commit | 0fdc26785d0a5bb33d9adb572307fd2d7a406734 (patch) | |
tree | 85474a5723bbf22117c654f357aaa26e9999fdce /net | |
parent | a92e5eb1103341e985a575e48e26f87fbb9b1679 (diff) |
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>
Diffstat (limited to 'net')
-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: | |||
1263 | return ret; | 1263 | return ret; |
1264 | } | 1264 | } |
1265 | 1265 | ||
1266 | DEFINE_SPINLOCK(use_gssp_lock); | 1266 | /* |
1267 | 1267 | * Try to set the sn->use_gss_proxy variable to a new value. We only allow | |
1268 | static bool use_gss_proxy(struct net *net) | 1268 | * it to be changed if it's currently undefined (-1). If it's any other value |
1269 | * then return -EBUSY unless the type wouldn't have changed anyway. | ||
1270 | */ | ||
1271 | static int set_gss_proxy(struct net *net, int type) | ||
1269 | { | 1272 | { |
1270 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1273 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1274 | int ret; | ||
1271 | 1275 | ||
1272 | if (sn->use_gss_proxy != -1) | 1276 | WARN_ON_ONCE(type != 0 && type != 1); |
1273 | return sn->use_gss_proxy; | 1277 | ret = cmpxchg(&sn->use_gss_proxy, -1, type); |
1274 | spin_lock(&use_gssp_lock); | 1278 | if (ret != -1 && ret != type) |
1275 | /* | 1279 | return -EBUSY; |
1276 | * If you wanted gss-proxy, you should have said so before | ||
1277 | * starting to accept requests: | ||
1278 | */ | ||
1279 | sn->use_gss_proxy = 0; | ||
1280 | spin_unlock(&use_gssp_lock); | ||
1281 | return 0; | 1280 | return 0; |
1282 | } | 1281 | } |
1283 | 1282 | ||
1284 | #ifdef CONFIG_PROC_FS | 1283 | static bool use_gss_proxy(struct net *net) |
1285 | |||
1286 | static int set_gss_proxy(struct net *net, int type) | ||
1287 | { | 1284 | { |
1288 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1285 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1289 | int ret = 0; | ||
1290 | 1286 | ||
1291 | WARN_ON_ONCE(type != 0 && type != 1); | 1287 | /* If use_gss_proxy is still undefined, then try to disable it */ |
1292 | spin_lock(&use_gssp_lock); | 1288 | if (sn->use_gss_proxy == -1) |
1293 | if (sn->use_gss_proxy == -1 || sn->use_gss_proxy == type) | 1289 | set_gss_proxy(net, 0); |
1294 | sn->use_gss_proxy = type; | 1290 | return sn->use_gss_proxy; |
1295 | else | ||
1296 | ret = -EBUSY; | ||
1297 | spin_unlock(&use_gssp_lock); | ||
1298 | return ret; | ||
1299 | } | 1291 | } |
1300 | 1292 | ||
1293 | #ifdef CONFIG_PROC_FS | ||
1294 | |||
1301 | static ssize_t write_gssp(struct file *file, const char __user *buf, | 1295 | static ssize_t write_gssp(struct file *file, const char __user *buf, |
1302 | size_t count, loff_t *ppos) | 1296 | size_t count, loff_t *ppos) |
1303 | { | 1297 | { |