diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 64 |
1 files changed, 61 insertions, 3 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 51aa27d32b5a..e451d104a434 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -75,7 +75,12 @@ struct gss_auth { | |||
75 | struct dentry *dentry; | 75 | struct dentry *dentry; |
76 | }; | 76 | }; |
77 | 77 | ||
78 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | ||
79 | static int pipe_version = -1; | ||
78 | static atomic_t pipe_users = ATOMIC_INIT(0); | 80 | static atomic_t pipe_users = ATOMIC_INIT(0); |
81 | static DEFINE_SPINLOCK(pipe_version_lock); | ||
82 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | ||
83 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | ||
79 | 84 | ||
80 | static void gss_free_ctx(struct gss_cl_ctx *); | 85 | static void gss_free_ctx(struct gss_cl_ctx *); |
81 | static struct rpc_pipe_ops gss_upcall_ops; | 86 | static struct rpc_pipe_ops gss_upcall_ops; |
@@ -234,12 +239,34 @@ struct gss_upcall_msg { | |||
234 | struct gss_cl_ctx *ctx; | 239 | struct gss_cl_ctx *ctx; |
235 | }; | 240 | }; |
236 | 241 | ||
242 | static int get_pipe_version(void) | ||
243 | { | ||
244 | int ret; | ||
245 | |||
246 | spin_lock(&pipe_version_lock); | ||
247 | if (pipe_version >= 0) { | ||
248 | atomic_inc(&pipe_users); | ||
249 | ret = 0; | ||
250 | } else | ||
251 | ret = -EAGAIN; | ||
252 | spin_unlock(&pipe_version_lock); | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | static void put_pipe_version(void) | ||
257 | { | ||
258 | if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { | ||
259 | pipe_version = -1; | ||
260 | spin_unlock(&pipe_version_lock); | ||
261 | } | ||
262 | } | ||
263 | |||
237 | static void | 264 | static void |
238 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 265 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
239 | { | 266 | { |
240 | if (!atomic_dec_and_test(&gss_msg->count)) | 267 | if (!atomic_dec_and_test(&gss_msg->count)) |
241 | return; | 268 | return; |
242 | atomic_dec(&pipe_users); | 269 | put_pipe_version(); |
243 | BUG_ON(!list_empty(&gss_msg->list)); | 270 | BUG_ON(!list_empty(&gss_msg->list)); |
244 | if (gss_msg->ctx != NULL) | 271 | if (gss_msg->ctx != NULL) |
245 | gss_put_ctx(gss_msg->ctx); | 272 | gss_put_ctx(gss_msg->ctx); |
@@ -330,11 +357,16 @@ static inline struct gss_upcall_msg * | |||
330 | gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) | 357 | gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) |
331 | { | 358 | { |
332 | struct gss_upcall_msg *gss_msg; | 359 | struct gss_upcall_msg *gss_msg; |
360 | int vers; | ||
333 | 361 | ||
334 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 362 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
335 | if (gss_msg == NULL) | 363 | if (gss_msg == NULL) |
336 | return ERR_PTR(-ENOMEM); | 364 | return ERR_PTR(-ENOMEM); |
337 | atomic_inc(&pipe_users); | 365 | vers = get_pipe_version(); |
366 | if (vers < 0) { | ||
367 | kfree(gss_msg); | ||
368 | return ERR_PTR(vers); | ||
369 | } | ||
338 | INIT_LIST_HEAD(&gss_msg->list); | 370 | INIT_LIST_HEAD(&gss_msg->list); |
339 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 371 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); |
340 | init_waitqueue_head(&gss_msg->waitqueue); | 372 | init_waitqueue_head(&gss_msg->waitqueue); |
@@ -400,6 +432,14 @@ gss_refresh_upcall(struct rpc_task *task) | |||
400 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, | 432 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, |
401 | cred->cr_uid); | 433 | cred->cr_uid); |
402 | gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); | 434 | gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); |
435 | if (IS_ERR(gss_msg) == -EAGAIN) { | ||
436 | /* XXX: warning on the first, under the assumption we | ||
437 | * shouldn't normally hit this case on a refresh. */ | ||
438 | warn_gssd(); | ||
439 | task->tk_timeout = 15*HZ; | ||
440 | rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL); | ||
441 | return 0; | ||
442 | } | ||
403 | if (IS_ERR(gss_msg)) { | 443 | if (IS_ERR(gss_msg)) { |
404 | err = PTR_ERR(gss_msg); | 444 | err = PTR_ERR(gss_msg); |
405 | goto out; | 445 | goto out; |
@@ -437,7 +477,17 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
437 | int err = 0; | 477 | int err = 0; |
438 | 478 | ||
439 | dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); | 479 | dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); |
480 | retry: | ||
440 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 481 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); |
482 | if (PTR_ERR(gss_msg) == -EAGAIN) { | ||
483 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | ||
484 | pipe_version >= 0, 15*HZ); | ||
485 | if (err) | ||
486 | goto out; | ||
487 | if (pipe_version < 0) | ||
488 | warn_gssd(); | ||
489 | goto retry; | ||
490 | } | ||
441 | if (IS_ERR(gss_msg)) { | 491 | if (IS_ERR(gss_msg)) { |
442 | err = PTR_ERR(gss_msg); | 492 | err = PTR_ERR(gss_msg); |
443 | goto out; | 493 | goto out; |
@@ -562,7 +612,14 @@ out: | |||
562 | static int | 612 | static int |
563 | gss_pipe_open(struct inode *inode) | 613 | gss_pipe_open(struct inode *inode) |
564 | { | 614 | { |
615 | spin_lock(&pipe_version_lock); | ||
616 | if (pipe_version < 0) { | ||
617 | pipe_version = 0; | ||
618 | rpc_wake_up(&pipe_version_rpc_waitqueue); | ||
619 | wake_up(&pipe_version_waitqueue); | ||
620 | } | ||
565 | atomic_inc(&pipe_users); | 621 | atomic_inc(&pipe_users); |
622 | spin_unlock(&pipe_version_lock); | ||
566 | return 0; | 623 | return 0; |
567 | } | 624 | } |
568 | 625 | ||
@@ -586,7 +643,7 @@ gss_pipe_release(struct inode *inode) | |||
586 | } | 643 | } |
587 | spin_unlock(&inode->i_lock); | 644 | spin_unlock(&inode->i_lock); |
588 | 645 | ||
589 | atomic_dec(&pipe_users); | 646 | put_pipe_version(); |
590 | } | 647 | } |
591 | 648 | ||
592 | static void | 649 | static void |
@@ -1379,6 +1436,7 @@ static int __init init_rpcsec_gss(void) | |||
1379 | err = gss_svc_init(); | 1436 | err = gss_svc_init(); |
1380 | if (err) | 1437 | if (err) |
1381 | goto out_unregister; | 1438 | goto out_unregister; |
1439 | rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version"); | ||
1382 | return 0; | 1440 | return 0; |
1383 | out_unregister: | 1441 | out_unregister: |
1384 | rpcauth_unregister(&authgss_ops); | 1442 | rpcauth_unregister(&authgss_ops); |