Commit 5d28dc82 authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Convert gss_ctx_lock to an RCU lock

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent f5c2187c
...@@ -75,6 +75,7 @@ struct gss_cl_ctx { ...@@ -75,6 +75,7 @@ struct gss_cl_ctx {
struct xdr_netobj gc_wire_ctx; struct xdr_netobj gc_wire_ctx;
u32 gc_win; u32 gc_win;
unsigned long gc_expiry; unsigned long gc_expiry;
struct rcu_head gc_rcu;
}; };
struct gss_upcall_msg; struct gss_upcall_msg;
......
...@@ -78,8 +78,6 @@ static const struct rpc_credops gss_credops; ...@@ -78,8 +78,6 @@ static const struct rpc_credops gss_credops;
/* dump the buffer in `emacs-hexl' style */ /* dump the buffer in `emacs-hexl' style */
#define isprint(c) ((c > 0x1f) && (c < 0x7f)) #define isprint(c) ((c > 0x1f) && (c < 0x7f))
static DEFINE_RWLOCK(gss_ctx_lock);
struct gss_auth { struct gss_auth {
struct rpc_auth rpc_auth; struct rpc_auth rpc_auth;
struct gss_api_mech *mech; struct gss_api_mech *mech;
...@@ -88,7 +86,7 @@ struct gss_auth { ...@@ -88,7 +86,7 @@ struct gss_auth {
struct dentry *dentry; struct dentry *dentry;
}; };
static void gss_destroy_ctx(struct gss_cl_ctx *); static void gss_free_ctx(struct gss_cl_ctx *);
static struct rpc_pipe_ops gss_upcall_ops; static struct rpc_pipe_ops gss_upcall_ops;
static inline struct gss_cl_ctx * static inline struct gss_cl_ctx *
...@@ -102,20 +100,24 @@ static inline void ...@@ -102,20 +100,24 @@ static inline void
gss_put_ctx(struct gss_cl_ctx *ctx) gss_put_ctx(struct gss_cl_ctx *ctx)
{ {
if (atomic_dec_and_test(&ctx->count)) if (atomic_dec_and_test(&ctx->count))
gss_destroy_ctx(ctx); gss_free_ctx(ctx);
} }
/* gss_cred_set_ctx:
* called by gss_upcall_callback and gss_create_upcall in order
* to set the gss context. The actual exchange of an old context
* and a new one is protected by the inode->i_lock.
*/
static void static void
gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
{ {
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *old; struct gss_cl_ctx *old;
write_lock(&gss_ctx_lock);
old = gss_cred->gc_ctx; old = gss_cred->gc_ctx;
gss_cred->gc_ctx = ctx; rcu_assign_pointer(gss_cred->gc_ctx, ctx);
set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
write_unlock(&gss_ctx_lock);
if (old) if (old)
gss_put_ctx(old); gss_put_ctx(old);
} }
...@@ -126,10 +128,10 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred) ...@@ -126,10 +128,10 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
int res = 0; int res = 0;
read_lock(&gss_ctx_lock); rcu_read_lock();
if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx) if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
res = 1; res = 1;
read_unlock(&gss_ctx_lock); rcu_read_unlock();
return res; return res;
} }
...@@ -168,10 +170,10 @@ gss_cred_get_ctx(struct rpc_cred *cred) ...@@ -168,10 +170,10 @@ gss_cred_get_ctx(struct rpc_cred *cred)
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx = NULL; struct gss_cl_ctx *ctx = NULL;
read_lock(&gss_ctx_lock); rcu_read_lock();
if (gss_cred->gc_ctx) if (gss_cred->gc_ctx)
ctx = gss_get_ctx(gss_cred->gc_ctx); ctx = gss_get_ctx(gss_cred->gc_ctx);
read_unlock(&gss_ctx_lock); rcu_read_unlock();
return ctx; return ctx;
} }
...@@ -333,11 +335,11 @@ gss_upcall_callback(struct rpc_task *task) ...@@ -333,11 +335,11 @@ gss_upcall_callback(struct rpc_task *task)
struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
struct inode *inode = gss_msg->auth->dentry->d_inode; struct inode *inode = gss_msg->auth->dentry->d_inode;
spin_lock(&inode->i_lock);
if (gss_msg->ctx) if (gss_msg->ctx)
gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
else else
task->tk_status = gss_msg->msg.errno; task->tk_status = gss_msg->msg.errno;
spin_lock(&inode->i_lock);
gss_cred->gc_upcall = NULL; gss_cred->gc_upcall = NULL;
rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -440,7 +442,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) ...@@ -440,7 +442,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
spin_unlock(&inode->i_lock);
break; break;
} }
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -454,6 +455,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) ...@@ -454,6 +455,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
else else
err = gss_msg->msg.errno; err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
out_intr: out_intr:
finish_wait(&gss_msg->waitqueue, &wait); finish_wait(&gss_msg->waitqueue, &wait);
gss_release_msg(gss_msg); gss_release_msg(gss_msg);
...@@ -681,9 +683,9 @@ gss_destroy(struct rpc_auth *auth) ...@@ -681,9 +683,9 @@ gss_destroy(struct rpc_auth *auth)
* to create a new cred or context, so they check that things have been * to create a new cred or context, so they check that things have been
* allocated before freeing them. */ * allocated before freeing them. */
static void static void
gss_destroy_ctx(struct gss_cl_ctx *ctx) gss_do_free_ctx(struct gss_cl_ctx *ctx)
{ {
dprintk("RPC: gss_destroy_ctx\n"); dprintk("RPC: gss_free_ctx\n");
if (ctx->gc_gss_ctx) if (ctx->gc_gss_ctx)
gss_delete_sec_context(&ctx->gc_gss_ctx); gss_delete_sec_context(&ctx->gc_gss_ctx);
...@@ -692,12 +694,23 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx) ...@@ -692,12 +694,23 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx)
kfree(ctx); kfree(ctx);
} }
static void
gss_free_ctx_callback(struct rcu_head *head)
{
struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu);
gss_do_free_ctx(ctx);
}
static void
gss_free_ctx(struct gss_cl_ctx *ctx)
{
call_rcu(&ctx->gc_rcu, gss_free_ctx_callback);
}
static void static void
gss_free_cred(struct gss_cred *gss_cred) gss_free_cred(struct gss_cred *gss_cred)
{ {
dprintk("RPC: gss_free_cred %p\n", gss_cred); dprintk("RPC: gss_free_cred %p\n", gss_cred);
if (gss_cred->gc_ctx)
gss_put_ctx(gss_cred->gc_ctx);
kfree(gss_cred); kfree(gss_cred);
} }
...@@ -711,7 +724,13 @@ gss_free_cred_callback(struct rcu_head *head) ...@@ -711,7 +724,13 @@ gss_free_cred_callback(struct rcu_head *head)
static void static void
gss_destroy_cred(struct rpc_cred *cred) gss_destroy_cred(struct rpc_cred *cred)
{ {
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx = gss_cred->gc_ctx;
rcu_assign_pointer(gss_cred->gc_ctx, NULL);
call_rcu(&cred->cr_rcu, gss_free_cred_callback); call_rcu(&cred->cr_rcu, gss_free_cred_callback);
if (ctx)
gss_put_ctx(ctx);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment