diff options
Diffstat (limited to 'net/sunrpc/auth_gss/auth_gss.c')
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 7da6b457f66a..fc2f78d6a9b4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -52,6 +52,8 @@ | |||
| 52 | #include <linux/sunrpc/gss_api.h> | 52 | #include <linux/sunrpc/gss_api.h> |
| 53 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
| 54 | 54 | ||
| 55 | #include "../netns.h" | ||
| 56 | |||
| 55 | static const struct rpc_authops authgss_ops; | 57 | static const struct rpc_authops authgss_ops; |
| 56 | 58 | ||
| 57 | static const struct rpc_credops gss_credops; | 59 | static const struct rpc_credops gss_credops; |
| @@ -85,8 +87,6 @@ struct gss_auth { | |||
| 85 | }; | 87 | }; |
| 86 | 88 | ||
| 87 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | 89 | /* pipe_version >= 0 if and only if someone has a pipe open. */ |
| 88 | static int pipe_version = -1; | ||
| 89 | static atomic_t pipe_users = ATOMIC_INIT(0); | ||
| 90 | static DEFINE_SPINLOCK(pipe_version_lock); | 90 | static DEFINE_SPINLOCK(pipe_version_lock); |
| 91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | 91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; |
| 92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | 92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); |
| @@ -266,24 +266,27 @@ struct gss_upcall_msg { | |||
| 266 | char databuf[UPCALL_BUF_LEN]; | 266 | char databuf[UPCALL_BUF_LEN]; |
| 267 | }; | 267 | }; |
| 268 | 268 | ||
| 269 | static int get_pipe_version(void) | 269 | static int get_pipe_version(struct net *net) |
| 270 | { | 270 | { |
| 271 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 271 | int ret; | 272 | int ret; |
| 272 | 273 | ||
| 273 | spin_lock(&pipe_version_lock); | 274 | spin_lock(&pipe_version_lock); |
| 274 | if (pipe_version >= 0) { | 275 | if (sn->pipe_version >= 0) { |
| 275 | atomic_inc(&pipe_users); | 276 | atomic_inc(&sn->pipe_users); |
| 276 | ret = pipe_version; | 277 | ret = sn->pipe_version; |
| 277 | } else | 278 | } else |
| 278 | ret = -EAGAIN; | 279 | ret = -EAGAIN; |
| 279 | spin_unlock(&pipe_version_lock); | 280 | spin_unlock(&pipe_version_lock); |
| 280 | return ret; | 281 | return ret; |
| 281 | } | 282 | } |
| 282 | 283 | ||
| 283 | static void put_pipe_version(void) | 284 | static void put_pipe_version(struct net *net) |
| 284 | { | 285 | { |
| 285 | if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { | 286 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 286 | pipe_version = -1; | 287 | |
| 288 | if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) { | ||
| 289 | sn->pipe_version = -1; | ||
| 287 | spin_unlock(&pipe_version_lock); | 290 | spin_unlock(&pipe_version_lock); |
| 288 | } | 291 | } |
| 289 | } | 292 | } |
| @@ -291,9 +294,10 @@ static void put_pipe_version(void) | |||
| 291 | static void | 294 | static void |
| 292 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 295 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
| 293 | { | 296 | { |
| 297 | struct net *net = rpc_net_ns(gss_msg->auth->client); | ||
| 294 | if (!atomic_dec_and_test(&gss_msg->count)) | 298 | if (!atomic_dec_and_test(&gss_msg->count)) |
| 295 | return; | 299 | return; |
| 296 | put_pipe_version(); | 300 | put_pipe_version(net); |
| 297 | BUG_ON(!list_empty(&gss_msg->list)); | 301 | BUG_ON(!list_empty(&gss_msg->list)); |
| 298 | if (gss_msg->ctx != NULL) | 302 | if (gss_msg->ctx != NULL) |
| 299 | gss_put_ctx(gss_msg->ctx); | 303 | gss_put_ctx(gss_msg->ctx); |
| @@ -439,7 +443,10 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg, | |||
| 439 | struct rpc_clnt *clnt, | 443 | struct rpc_clnt *clnt, |
| 440 | const char *service_name) | 444 | const char *service_name) |
| 441 | { | 445 | { |
| 442 | if (pipe_version == 0) | 446 | struct net *net = rpc_net_ns(clnt); |
| 447 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 448 | |||
| 449 | if (sn->pipe_version == 0) | ||
| 443 | gss_encode_v0_msg(gss_msg); | 450 | gss_encode_v0_msg(gss_msg); |
| 444 | else /* pipe_version == 1 */ | 451 | else /* pipe_version == 1 */ |
| 445 | gss_encode_v1_msg(gss_msg, clnt, service_name); | 452 | gss_encode_v1_msg(gss_msg, clnt, service_name); |
| @@ -455,7 +462,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | |||
| 455 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 462 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
| 456 | if (gss_msg == NULL) | 463 | if (gss_msg == NULL) |
| 457 | return ERR_PTR(-ENOMEM); | 464 | return ERR_PTR(-ENOMEM); |
| 458 | vers = get_pipe_version(); | 465 | vers = get_pipe_version(rpc_net_ns(clnt)); |
| 459 | if (vers < 0) { | 466 | if (vers < 0) { |
| 460 | kfree(gss_msg); | 467 | kfree(gss_msg); |
| 461 | return ERR_PTR(vers); | 468 | return ERR_PTR(vers); |
| @@ -559,24 +566,34 @@ out: | |||
| 559 | static inline int | 566 | static inline int |
| 560 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 567 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
| 561 | { | 568 | { |
| 569 | struct net *net = rpc_net_ns(gss_auth->client); | ||
| 570 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 562 | struct rpc_pipe *pipe; | 571 | struct rpc_pipe *pipe; |
| 563 | struct rpc_cred *cred = &gss_cred->gc_base; | 572 | struct rpc_cred *cred = &gss_cred->gc_base; |
| 564 | struct gss_upcall_msg *gss_msg; | 573 | struct gss_upcall_msg *gss_msg; |
| 574 | unsigned long timeout; | ||
| 565 | DEFINE_WAIT(wait); | 575 | DEFINE_WAIT(wait); |
| 566 | int err = 0; | 576 | int err; |
| 567 | 577 | ||
| 568 | dprintk("RPC: %s for uid %u\n", | 578 | dprintk("RPC: %s for uid %u\n", |
| 569 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); | 579 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); |
| 570 | retry: | 580 | retry: |
| 581 | err = 0; | ||
| 582 | /* Default timeout is 15s unless we know that gssd is not running */ | ||
| 583 | timeout = 15 * HZ; | ||
| 584 | if (!sn->gssd_running) | ||
| 585 | timeout = HZ >> 2; | ||
| 571 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 586 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); |
| 572 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 587 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
| 573 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 588 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
| 574 | pipe_version >= 0, 15*HZ); | 589 | sn->pipe_version >= 0, timeout); |
| 575 | if (pipe_version < 0) { | 590 | if (sn->pipe_version < 0) { |
| 591 | if (err == 0) | ||
| 592 | sn->gssd_running = 0; | ||
| 576 | warn_gssd(); | 593 | warn_gssd(); |
| 577 | err = -EACCES; | 594 | err = -EACCES; |
| 578 | } | 595 | } |
| 579 | if (err) | 596 | if (err < 0) |
| 580 | goto out; | 597 | goto out; |
| 581 | goto retry; | 598 | goto retry; |
| 582 | } | 599 | } |
| @@ -707,20 +724,22 @@ out: | |||
| 707 | 724 | ||
| 708 | static int gss_pipe_open(struct inode *inode, int new_version) | 725 | static int gss_pipe_open(struct inode *inode, int new_version) |
| 709 | { | 726 | { |
| 727 | struct net *net = inode->i_sb->s_fs_info; | ||
| 728 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 710 | int ret = 0; | 729 | int ret = 0; |
| 711 | 730 | ||
| 712 | spin_lock(&pipe_version_lock); | 731 | spin_lock(&pipe_version_lock); |
| 713 | if (pipe_version < 0) { | 732 | if (sn->pipe_version < 0) { |
| 714 | /* First open of any gss pipe determines the version: */ | 733 | /* First open of any gss pipe determines the version: */ |
| 715 | pipe_version = new_version; | 734 | sn->pipe_version = new_version; |
| 716 | rpc_wake_up(&pipe_version_rpc_waitqueue); | 735 | rpc_wake_up(&pipe_version_rpc_waitqueue); |
| 717 | wake_up(&pipe_version_waitqueue); | 736 | wake_up(&pipe_version_waitqueue); |
| 718 | } else if (pipe_version != new_version) { | 737 | } else if (sn->pipe_version != new_version) { |
| 719 | /* Trying to open a pipe of a different version */ | 738 | /* Trying to open a pipe of a different version */ |
| 720 | ret = -EBUSY; | 739 | ret = -EBUSY; |
| 721 | goto out; | 740 | goto out; |
| 722 | } | 741 | } |
| 723 | atomic_inc(&pipe_users); | 742 | atomic_inc(&sn->pipe_users); |
| 724 | out: | 743 | out: |
| 725 | spin_unlock(&pipe_version_lock); | 744 | spin_unlock(&pipe_version_lock); |
| 726 | return ret; | 745 | return ret; |
| @@ -740,6 +759,7 @@ static int gss_pipe_open_v1(struct inode *inode) | |||
| 740 | static void | 759 | static void |
| 741 | gss_pipe_release(struct inode *inode) | 760 | gss_pipe_release(struct inode *inode) |
| 742 | { | 761 | { |
| 762 | struct net *net = inode->i_sb->s_fs_info; | ||
| 743 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; | 763 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; |
| 744 | struct gss_upcall_msg *gss_msg; | 764 | struct gss_upcall_msg *gss_msg; |
| 745 | 765 | ||
| @@ -758,7 +778,7 @@ restart: | |||
| 758 | } | 778 | } |
| 759 | spin_unlock(&pipe->lock); | 779 | spin_unlock(&pipe->lock); |
| 760 | 780 | ||
| 761 | put_pipe_version(); | 781 | put_pipe_version(net); |
| 762 | } | 782 | } |
| 763 | 783 | ||
| 764 | static void | 784 | static void |
