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 | |
| 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>
| -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); |
