diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-05-15 13:27:32 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-05-16 09:17:54 -0400 |
commit | 2aed8b476f3478be140df92bbfb182978e835504 (patch) | |
tree | 1ec837ead098b2eae7e4d8a8ad5f325c7591285e | |
parent | abfdbd53a4e28844ad953b313f017f55edbb85b7 (diff) |
SUNRPC: Convert auth_gss pipe detection to work in namespaces
This seems to have been overlooked when we did the namespace
conversion. If a container is running a legacy version of rpc.gssd
then it will be disrupted if the global 'pipe_version' is set by a
container running the new version of rpc.gssd.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 46 | ||||
-rw-r--r-- | net/sunrpc/netns.h | 2 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 1 |
3 files changed, 30 insertions, 19 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 3aff72f78bf2..fc2f78d6a9b4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -87,8 +87,6 @@ struct gss_auth { | |||
87 | }; | 87 | }; |
88 | 88 | ||
89 | /* 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. */ |
90 | static int pipe_version = -1; | ||
91 | static atomic_t pipe_users = ATOMIC_INIT(0); | ||
92 | static DEFINE_SPINLOCK(pipe_version_lock); | 90 | static DEFINE_SPINLOCK(pipe_version_lock); |
93 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | 91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; |
94 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | 92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); |
@@ -268,24 +266,27 @@ struct gss_upcall_msg { | |||
268 | char databuf[UPCALL_BUF_LEN]; | 266 | char databuf[UPCALL_BUF_LEN]; |
269 | }; | 267 | }; |
270 | 268 | ||
271 | static int get_pipe_version(void) | 269 | static int get_pipe_version(struct net *net) |
272 | { | 270 | { |
271 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
273 | int ret; | 272 | int ret; |
274 | 273 | ||
275 | spin_lock(&pipe_version_lock); | 274 | spin_lock(&pipe_version_lock); |
276 | if (pipe_version >= 0) { | 275 | if (sn->pipe_version >= 0) { |
277 | atomic_inc(&pipe_users); | 276 | atomic_inc(&sn->pipe_users); |
278 | ret = pipe_version; | 277 | ret = sn->pipe_version; |
279 | } else | 278 | } else |
280 | ret = -EAGAIN; | 279 | ret = -EAGAIN; |
281 | spin_unlock(&pipe_version_lock); | 280 | spin_unlock(&pipe_version_lock); |
282 | return ret; | 281 | return ret; |
283 | } | 282 | } |
284 | 283 | ||
285 | static void put_pipe_version(void) | 284 | static void put_pipe_version(struct net *net) |
286 | { | 285 | { |
287 | if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { | 286 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
288 | pipe_version = -1; | 287 | |
288 | if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) { | ||
289 | sn->pipe_version = -1; | ||
289 | spin_unlock(&pipe_version_lock); | 290 | spin_unlock(&pipe_version_lock); |
290 | } | 291 | } |
291 | } | 292 | } |
@@ -293,9 +294,10 @@ static void put_pipe_version(void) | |||
293 | static void | 294 | static void |
294 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 295 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
295 | { | 296 | { |
297 | struct net *net = rpc_net_ns(gss_msg->auth->client); | ||
296 | if (!atomic_dec_and_test(&gss_msg->count)) | 298 | if (!atomic_dec_and_test(&gss_msg->count)) |
297 | return; | 299 | return; |
298 | put_pipe_version(); | 300 | put_pipe_version(net); |
299 | BUG_ON(!list_empty(&gss_msg->list)); | 301 | BUG_ON(!list_empty(&gss_msg->list)); |
300 | if (gss_msg->ctx != NULL) | 302 | if (gss_msg->ctx != NULL) |
301 | gss_put_ctx(gss_msg->ctx); | 303 | gss_put_ctx(gss_msg->ctx); |
@@ -441,7 +443,10 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg, | |||
441 | struct rpc_clnt *clnt, | 443 | struct rpc_clnt *clnt, |
442 | const char *service_name) | 444 | const char *service_name) |
443 | { | 445 | { |
444 | 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) | ||
445 | gss_encode_v0_msg(gss_msg); | 450 | gss_encode_v0_msg(gss_msg); |
446 | else /* pipe_version == 1 */ | 451 | else /* pipe_version == 1 */ |
447 | gss_encode_v1_msg(gss_msg, clnt, service_name); | 452 | gss_encode_v1_msg(gss_msg, clnt, service_name); |
@@ -457,7 +462,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | |||
457 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 462 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
458 | if (gss_msg == NULL) | 463 | if (gss_msg == NULL) |
459 | return ERR_PTR(-ENOMEM); | 464 | return ERR_PTR(-ENOMEM); |
460 | vers = get_pipe_version(); | 465 | vers = get_pipe_version(rpc_net_ns(clnt)); |
461 | if (vers < 0) { | 466 | if (vers < 0) { |
462 | kfree(gss_msg); | 467 | kfree(gss_msg); |
463 | return ERR_PTR(vers); | 468 | return ERR_PTR(vers); |
@@ -581,8 +586,8 @@ retry: | |||
581 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 586 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); |
582 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 587 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
583 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 588 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
584 | pipe_version >= 0, timeout); | 589 | sn->pipe_version >= 0, timeout); |
585 | if (pipe_version < 0) { | 590 | if (sn->pipe_version < 0) { |
586 | if (err == 0) | 591 | if (err == 0) |
587 | sn->gssd_running = 0; | 592 | sn->gssd_running = 0; |
588 | warn_gssd(); | 593 | warn_gssd(); |
@@ -719,20 +724,22 @@ out: | |||
719 | 724 | ||
720 | static int gss_pipe_open(struct inode *inode, int new_version) | 725 | static int gss_pipe_open(struct inode *inode, int new_version) |
721 | { | 726 | { |
727 | struct net *net = inode->i_sb->s_fs_info; | ||
728 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
722 | int ret = 0; | 729 | int ret = 0; |
723 | 730 | ||
724 | spin_lock(&pipe_version_lock); | 731 | spin_lock(&pipe_version_lock); |
725 | if (pipe_version < 0) { | 732 | if (sn->pipe_version < 0) { |
726 | /* First open of any gss pipe determines the version: */ | 733 | /* First open of any gss pipe determines the version: */ |
727 | pipe_version = new_version; | 734 | sn->pipe_version = new_version; |
728 | rpc_wake_up(&pipe_version_rpc_waitqueue); | 735 | rpc_wake_up(&pipe_version_rpc_waitqueue); |
729 | wake_up(&pipe_version_waitqueue); | 736 | wake_up(&pipe_version_waitqueue); |
730 | } else if (pipe_version != new_version) { | 737 | } else if (sn->pipe_version != new_version) { |
731 | /* Trying to open a pipe of a different version */ | 738 | /* Trying to open a pipe of a different version */ |
732 | ret = -EBUSY; | 739 | ret = -EBUSY; |
733 | goto out; | 740 | goto out; |
734 | } | 741 | } |
735 | atomic_inc(&pipe_users); | 742 | atomic_inc(&sn->pipe_users); |
736 | out: | 743 | out: |
737 | spin_unlock(&pipe_version_lock); | 744 | spin_unlock(&pipe_version_lock); |
738 | return ret; | 745 | return ret; |
@@ -752,6 +759,7 @@ static int gss_pipe_open_v1(struct inode *inode) | |||
752 | static void | 759 | static void |
753 | gss_pipe_release(struct inode *inode) | 760 | gss_pipe_release(struct inode *inode) |
754 | { | 761 | { |
762 | struct net *net = inode->i_sb->s_fs_info; | ||
755 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; | 763 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; |
756 | struct gss_upcall_msg *gss_msg; | 764 | struct gss_upcall_msg *gss_msg; |
757 | 765 | ||
@@ -770,7 +778,7 @@ restart: | |||
770 | } | 778 | } |
771 | spin_unlock(&pipe->lock); | 779 | spin_unlock(&pipe->lock); |
772 | 780 | ||
773 | put_pipe_version(); | 781 | put_pipe_version(net); |
774 | } | 782 | } |
775 | 783 | ||
776 | static void | 784 | static void |
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 0827f641e8d7..74d948f5d5a1 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h | |||
@@ -28,6 +28,8 @@ struct sunrpc_net { | |||
28 | wait_queue_head_t gssp_wq; | 28 | wait_queue_head_t gssp_wq; |
29 | struct rpc_clnt *gssp_clnt; | 29 | struct rpc_clnt *gssp_clnt; |
30 | int use_gss_proxy; | 30 | int use_gss_proxy; |
31 | int pipe_version; | ||
32 | atomic_t pipe_users; | ||
31 | struct proc_dir_entry *use_gssp_proc; | 33 | struct proc_dir_entry *use_gssp_proc; |
32 | 34 | ||
33 | unsigned int gssd_running; | 35 | unsigned int gssd_running; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index a370762e459d..e7ce4b3eb0bd 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -1073,6 +1073,7 @@ void rpc_pipefs_init_net(struct net *net) | |||
1073 | 1073 | ||
1074 | mutex_init(&sn->pipefs_sb_lock); | 1074 | mutex_init(&sn->pipefs_sb_lock); |
1075 | sn->gssd_running = 1; | 1075 | sn->gssd_running = 1; |
1076 | sn->pipe_version = -1; | ||
1076 | } | 1077 | } |
1077 | 1078 | ||
1078 | /* | 1079 | /* |