diff options
-rw-r--r-- | include/linux/sunrpc/auth_gss.h | 1 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 53 |
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 | ||
80 | struct gss_upcall_msg; | 81 | struct 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 | ||
81 | static DEFINE_RWLOCK(gss_ctx_lock); | ||
82 | |||
83 | struct gss_auth { | 81 | struct 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 | ||
91 | static void gss_destroy_ctx(struct gss_cl_ctx *); | 89 | static void gss_free_ctx(struct gss_cl_ctx *); |
92 | static struct rpc_pipe_ops gss_upcall_ops; | 90 | static struct rpc_pipe_ops gss_upcall_ops; |
93 | 91 | ||
94 | static inline struct gss_cl_ctx * | 92 | static inline struct gss_cl_ctx * |
@@ -102,20 +100,24 @@ static inline void | |||
102 | gss_put_ctx(struct gss_cl_ctx *ctx) | 100 | gss_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 | */ | ||
108 | static void | 111 | static void |
109 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | 112 | gss_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); | ||
457 | out_intr: | 459 | out_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. */ |
683 | static void | 685 | static void |
684 | gss_destroy_ctx(struct gss_cl_ctx *ctx) | 686 | gss_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 | ||
695 | static void | 697 | static void |
698 | gss_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 | |||
704 | static void | ||
705 | gss_free_ctx(struct gss_cl_ctx *ctx) | ||
706 | { | ||
707 | call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); | ||
708 | } | ||
709 | |||
710 | static void | ||
696 | gss_free_cred(struct gss_cred *gss_cred) | 711 | gss_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) | |||
711 | static void | 724 | static void |
712 | gss_destroy_cred(struct rpc_cred *cred) | 725 | gss_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 | /* |