diff options
| -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); |
