aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/auth_gss.h1
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c53
2 files changed, 37 insertions, 17 deletions
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h
index 0bd1d06777b9..67658e17a375 100644
--- a/include/linux/sunrpc/auth_gss.h
+++ b/include/linux/sunrpc/auth_gss.h
@@ -75,6 +75,7 @@ struct gss_cl_ctx {
75 struct xdr_netobj gc_wire_ctx; 75 struct xdr_netobj gc_wire_ctx;
76 u32 gc_win; 76 u32 gc_win;
77 unsigned long gc_expiry; 77 unsigned long gc_expiry;
78 struct rcu_head gc_rcu;
78}; 79};
79 80
80struct gss_upcall_msg; 81struct gss_upcall_msg;
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 8653a92144ae..15da6f82db36 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -78,8 +78,6 @@ static const struct rpc_credops gss_credops;
78/* dump the buffer in `emacs-hexl' style */ 78/* dump the buffer in `emacs-hexl' style */
79#define isprint(c) ((c > 0x1f) && (c < 0x7f)) 79#define isprint(c) ((c > 0x1f) && (c < 0x7f))
80 80
81static DEFINE_RWLOCK(gss_ctx_lock);
82
83struct gss_auth { 81struct gss_auth {
84 struct rpc_auth rpc_auth; 82 struct rpc_auth rpc_auth;
85 struct gss_api_mech *mech; 83 struct gss_api_mech *mech;
@@ -88,7 +86,7 @@ struct gss_auth {
88 struct dentry *dentry; 86 struct dentry *dentry;
89}; 87};
90 88
91static void gss_destroy_ctx(struct gss_cl_ctx *); 89static void gss_free_ctx(struct gss_cl_ctx *);
92static struct rpc_pipe_ops gss_upcall_ops; 90static struct rpc_pipe_ops gss_upcall_ops;
93 91
94static inline struct gss_cl_ctx * 92static inline struct gss_cl_ctx *
@@ -102,20 +100,24 @@ static inline void
102gss_put_ctx(struct gss_cl_ctx *ctx) 100gss_put_ctx(struct gss_cl_ctx *ctx)
103{ 101{
104 if (atomic_dec_and_test(&ctx->count)) 102 if (atomic_dec_and_test(&ctx->count))
105 gss_destroy_ctx(ctx); 103 gss_free_ctx(ctx);
106} 104}
107 105
106/* gss_cred_set_ctx:
107 * called by gss_upcall_callback and gss_create_upcall in order
108 * to set the gss context. The actual exchange of an old context
109 * and a new one is protected by the inode->i_lock.
110 */
108static void 111static void
109gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) 112gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
110{ 113{
111 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); 114 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
112 struct gss_cl_ctx *old; 115 struct gss_cl_ctx *old;
113 write_lock(&gss_ctx_lock); 116
114 old = gss_cred->gc_ctx; 117 old = gss_cred->gc_ctx;
115 gss_cred->gc_ctx = ctx; 118 rcu_assign_pointer(gss_cred->gc_ctx, ctx);
116 set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); 119 set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
117 clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); 120 clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
118 write_unlock(&gss_ctx_lock);
119 if (old) 121 if (old)
120 gss_put_ctx(old); 122 gss_put_ctx(old);
121} 123}
@@ -126,10 +128,10 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
126 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); 128 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
127 int res = 0; 129 int res = 0;
128 130
129 read_lock(&gss_ctx_lock); 131 rcu_read_lock();
130 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx) 132 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
131 res = 1; 133 res = 1;
132 read_unlock(&gss_ctx_lock); 134 rcu_read_unlock();
133 return res; 135 return res;
134} 136}
135 137
@@ -168,10 +170,10 @@ gss_cred_get_ctx(struct rpc_cred *cred)
168 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); 170 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
169 struct gss_cl_ctx *ctx = NULL; 171 struct gss_cl_ctx *ctx = NULL;
170 172
171 read_lock(&gss_ctx_lock); 173 rcu_read_lock();
172 if (gss_cred->gc_ctx) 174 if (gss_cred->gc_ctx)
173 ctx = gss_get_ctx(gss_cred->gc_ctx); 175 ctx = gss_get_ctx(gss_cred->gc_ctx);
174 read_unlock(&gss_ctx_lock); 176 rcu_read_unlock();
175 return ctx; 177 return ctx;
176} 178}
177 179
@@ -333,11 +335,11 @@ gss_upcall_callback(struct rpc_task *task)
333 struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; 335 struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
334 struct inode *inode = gss_msg->auth->dentry->d_inode; 336 struct inode *inode = gss_msg->auth->dentry->d_inode;
335 337
338 spin_lock(&inode->i_lock);
336 if (gss_msg->ctx) 339 if (gss_msg->ctx)
337 gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); 340 gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
338 else 341 else
339 task->tk_status = gss_msg->msg.errno; 342 task->tk_status = gss_msg->msg.errno;
340 spin_lock(&inode->i_lock);
341 gss_cred->gc_upcall = NULL; 343 gss_cred->gc_upcall = NULL;
342 rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); 344 rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
343 spin_unlock(&inode->i_lock); 345 spin_unlock(&inode->i_lock);
@@ -440,7 +442,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
440 prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); 442 prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE);
441 spin_lock(&inode->i_lock); 443 spin_lock(&inode->i_lock);
442 if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { 444 if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
443 spin_unlock(&inode->i_lock);
444 break; 445 break;
445 } 446 }
446 spin_unlock(&inode->i_lock); 447 spin_unlock(&inode->i_lock);
@@ -454,6 +455,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
454 gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); 455 gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
455 else 456 else
456 err = gss_msg->msg.errno; 457 err = gss_msg->msg.errno;
458 spin_unlock(&inode->i_lock);
457out_intr: 459out_intr:
458 finish_wait(&gss_msg->waitqueue, &wait); 460 finish_wait(&gss_msg->waitqueue, &wait);
459 gss_release_msg(gss_msg); 461 gss_release_msg(gss_msg);
@@ -681,9 +683,9 @@ gss_destroy(struct rpc_auth *auth)
681 * to create a new cred or context, so they check that things have been 683 * to create a new cred or context, so they check that things have been
682 * allocated before freeing them. */ 684 * allocated before freeing them. */
683static void 685static void
684gss_destroy_ctx(struct gss_cl_ctx *ctx) 686gss_do_free_ctx(struct gss_cl_ctx *ctx)
685{ 687{
686 dprintk("RPC: gss_destroy_ctx\n"); 688 dprintk("RPC: gss_free_ctx\n");
687 689
688 if (ctx->gc_gss_ctx) 690 if (ctx->gc_gss_ctx)
689 gss_delete_sec_context(&ctx->gc_gss_ctx); 691 gss_delete_sec_context(&ctx->gc_gss_ctx);
@@ -693,11 +695,22 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx)
693} 695}
694 696
695static void 697static void
698gss_free_ctx_callback(struct rcu_head *head)
699{
700 struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu);
701 gss_do_free_ctx(ctx);
702}
703
704static void
705gss_free_ctx(struct gss_cl_ctx *ctx)
706{
707 call_rcu(&ctx->gc_rcu, gss_free_ctx_callback);
708}
709
710static void
696gss_free_cred(struct gss_cred *gss_cred) 711gss_free_cred(struct gss_cred *gss_cred)
697{ 712{
698 dprintk("RPC: gss_free_cred %p\n", gss_cred); 713 dprintk("RPC: gss_free_cred %p\n", gss_cred);
699 if (gss_cred->gc_ctx)
700 gss_put_ctx(gss_cred->gc_ctx);
701 kfree(gss_cred); 714 kfree(gss_cred);
702} 715}
703 716
@@ -711,7 +724,13 @@ gss_free_cred_callback(struct rcu_head *head)
711static void 724static void
712gss_destroy_cred(struct rpc_cred *cred) 725gss_destroy_cred(struct rpc_cred *cred)
713{ 726{
727 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
728 struct gss_cl_ctx *ctx = gss_cred->gc_ctx;
729
730 rcu_assign_pointer(gss_cred->gc_ctx, NULL);
714 call_rcu(&cred->cr_rcu, gss_free_cred_callback); 731 call_rcu(&cred->cr_rcu, gss_free_cred_callback);
732 if (ctx)
733 gss_put_ctx(ctx);
715} 734}
716 735
717/* 736/*