diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-04-17 16:53:01 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-04-19 16:55:15 -0400 |
commit | 7b6962b0a6000df48c8a5fd967d262f77704101b (patch) | |
tree | 8902c9232242ac48c49f3e7a4ff0a94045974726 /net/sunrpc/auth_gss/auth_gss.c | |
parent | 7c1d71cf56feebfb5b98219b9d11dfc3a2feca62 (diff) |
SUNRPC: Fix a race in gss_refresh_upcall()
If the downcall completes before we get the spin_lock then we currently
fail to refresh the credential.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/auth_gss/auth_gss.c')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 46f7ec800af9..6f1b4e2f5e81 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -117,6 +117,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | |||
117 | struct gss_cl_ctx *old; | 117 | struct gss_cl_ctx *old; |
118 | 118 | ||
119 | old = gss_cred->gc_ctx; | 119 | old = gss_cred->gc_ctx; |
120 | gss_get_ctx(ctx); | ||
120 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); | 121 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); |
121 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 122 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
122 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); | 123 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); |
@@ -340,7 +341,7 @@ gss_upcall_callback(struct rpc_task *task) | |||
340 | 341 | ||
341 | spin_lock(&inode->i_lock); | 342 | spin_lock(&inode->i_lock); |
342 | if (gss_msg->ctx) | 343 | if (gss_msg->ctx) |
343 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); | 344 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); |
344 | else | 345 | else |
345 | task->tk_status = gss_msg->msg.errno; | 346 | task->tk_status = gss_msg->msg.errno; |
346 | gss_cred->gc_upcall = NULL; | 347 | gss_cred->gc_upcall = NULL; |
@@ -417,7 +418,11 @@ gss_refresh_upcall(struct rpc_task *task) | |||
417 | spin_lock(&inode->i_lock); | 418 | spin_lock(&inode->i_lock); |
418 | if (gss_cred->gc_upcall != NULL) | 419 | if (gss_cred->gc_upcall != NULL) |
419 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); | 420 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); |
420 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { | 421 | else if (gss_msg->ctx != NULL) { |
422 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); | ||
423 | gss_cred->gc_upcall = NULL; | ||
424 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | ||
425 | } else if (gss_msg->msg.errno >= 0) { | ||
421 | task->tk_timeout = 0; | 426 | task->tk_timeout = 0; |
422 | gss_cred->gc_upcall = gss_msg; | 427 | gss_cred->gc_upcall = gss_msg; |
423 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ | 428 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ |
@@ -462,7 +467,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
462 | schedule(); | 467 | schedule(); |
463 | } | 468 | } |
464 | if (gss_msg->ctx) | 469 | if (gss_msg->ctx) |
465 | gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); | 470 | gss_cred_set_ctx(cred, gss_msg->ctx); |
466 | else | 471 | else |
467 | err = gss_msg->msg.errno; | 472 | err = gss_msg->msg.errno; |
468 | spin_unlock(&inode->i_lock); | 473 | spin_unlock(&inode->i_lock); |