aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c64
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. */
79static int pipe_version = -1;
78static atomic_t pipe_users = ATOMIC_INIT(0); 80static atomic_t pipe_users = ATOMIC_INIT(0);
81static DEFINE_SPINLOCK(pipe_version_lock);
82static struct rpc_wait_queue pipe_version_rpc_waitqueue;
83static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
79 84
80static void gss_free_ctx(struct gss_cl_ctx *); 85static void gss_free_ctx(struct gss_cl_ctx *);
81static struct rpc_pipe_ops gss_upcall_ops; 86static 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
242static 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
256static 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
237static void 264static void
238gss_release_msg(struct gss_upcall_msg *gss_msg) 265gss_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 *
330gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) 357gss_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);
480retry:
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:
562static int 612static int
563gss_pipe_open(struct inode *inode) 613gss_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
592static void 649static 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;
1383out_unregister: 1441out_unregister:
1384 rpcauth_unregister(&authgss_ops); 1442 rpcauth_unregister(&authgss_ops);