diff options
Diffstat (limited to 'net/sunrpc/clnt.c')
| -rw-r--r-- | net/sunrpc/clnt.c | 221 |
1 files changed, 146 insertions, 75 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 154034b675bd..fa5549079d79 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -226,7 +226,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
| 226 | goto out_no_principal; | 226 | goto out_no_principal; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | kref_init(&clnt->cl_kref); | 229 | atomic_set(&clnt->cl_count, 1); |
| 230 | 230 | ||
| 231 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name); | 231 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name); |
| 232 | if (err < 0) | 232 | if (err < 0) |
| @@ -390,14 +390,14 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
| 390 | if (new->cl_principal == NULL) | 390 | if (new->cl_principal == NULL) |
| 391 | goto out_no_principal; | 391 | goto out_no_principal; |
| 392 | } | 392 | } |
| 393 | kref_init(&new->cl_kref); | 393 | atomic_set(&new->cl_count, 1); |
| 394 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); | 394 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); |
| 395 | if (err != 0) | 395 | if (err != 0) |
| 396 | goto out_no_path; | 396 | goto out_no_path; |
| 397 | if (new->cl_auth) | 397 | if (new->cl_auth) |
| 398 | atomic_inc(&new->cl_auth->au_count); | 398 | atomic_inc(&new->cl_auth->au_count); |
| 399 | xprt_get(clnt->cl_xprt); | 399 | xprt_get(clnt->cl_xprt); |
| 400 | kref_get(&clnt->cl_kref); | 400 | atomic_inc(&clnt->cl_count); |
| 401 | rpc_register_client(new); | 401 | rpc_register_client(new); |
| 402 | rpciod_up(); | 402 | rpciod_up(); |
| 403 | return new; | 403 | return new; |
| @@ -414,6 +414,35 @@ out_no_clnt: | |||
| 414 | EXPORT_SYMBOL_GPL(rpc_clone_client); | 414 | EXPORT_SYMBOL_GPL(rpc_clone_client); |
| 415 | 415 | ||
| 416 | /* | 416 | /* |
| 417 | * Kill all tasks for the given client. | ||
| 418 | * XXX: kill their descendants as well? | ||
| 419 | */ | ||
| 420 | void rpc_killall_tasks(struct rpc_clnt *clnt) | ||
| 421 | { | ||
| 422 | struct rpc_task *rovr; | ||
| 423 | |||
| 424 | |||
| 425 | if (list_empty(&clnt->cl_tasks)) | ||
| 426 | return; | ||
| 427 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
| 428 | /* | ||
| 429 | * Spin lock all_tasks to prevent changes... | ||
| 430 | */ | ||
| 431 | spin_lock(&clnt->cl_lock); | ||
| 432 | list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { | ||
| 433 | if (!RPC_IS_ACTIVATED(rovr)) | ||
| 434 | continue; | ||
| 435 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | ||
| 436 | rovr->tk_flags |= RPC_TASK_KILLED; | ||
| 437 | rpc_exit(rovr, -EIO); | ||
| 438 | rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | spin_unlock(&clnt->cl_lock); | ||
| 442 | } | ||
| 443 | EXPORT_SYMBOL_GPL(rpc_killall_tasks); | ||
| 444 | |||
| 445 | /* | ||
| 417 | * Properly shut down an RPC client, terminating all outstanding | 446 | * Properly shut down an RPC client, terminating all outstanding |
| 418 | * requests. | 447 | * requests. |
| 419 | */ | 448 | */ |
| @@ -436,10 +465,8 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client); | |||
| 436 | * Free an RPC client | 465 | * Free an RPC client |
| 437 | */ | 466 | */ |
| 438 | static void | 467 | static void |
| 439 | rpc_free_client(struct kref *kref) | 468 | rpc_free_client(struct rpc_clnt *clnt) |
| 440 | { | 469 | { |
| 441 | struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); | ||
| 442 | |||
| 443 | dprintk("RPC: destroying %s client for %s\n", | 470 | dprintk("RPC: destroying %s client for %s\n", |
| 444 | clnt->cl_protname, clnt->cl_server); | 471 | clnt->cl_protname, clnt->cl_server); |
| 445 | if (!IS_ERR(clnt->cl_path.dentry)) { | 472 | if (!IS_ERR(clnt->cl_path.dentry)) { |
| @@ -466,12 +493,10 @@ out_free: | |||
| 466 | * Free an RPC client | 493 | * Free an RPC client |
| 467 | */ | 494 | */ |
| 468 | static void | 495 | static void |
| 469 | rpc_free_auth(struct kref *kref) | 496 | rpc_free_auth(struct rpc_clnt *clnt) |
| 470 | { | 497 | { |
| 471 | struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); | ||
| 472 | |||
| 473 | if (clnt->cl_auth == NULL) { | 498 | if (clnt->cl_auth == NULL) { |
| 474 | rpc_free_client(kref); | 499 | rpc_free_client(clnt); |
| 475 | return; | 500 | return; |
| 476 | } | 501 | } |
| 477 | 502 | ||
| @@ -480,10 +505,11 @@ rpc_free_auth(struct kref *kref) | |||
| 480 | * release remaining GSS contexts. This mechanism ensures | 505 | * release remaining GSS contexts. This mechanism ensures |
| 481 | * that it can do so safely. | 506 | * that it can do so safely. |
| 482 | */ | 507 | */ |
| 483 | kref_init(kref); | 508 | atomic_inc(&clnt->cl_count); |
| 484 | rpcauth_release(clnt->cl_auth); | 509 | rpcauth_release(clnt->cl_auth); |
| 485 | clnt->cl_auth = NULL; | 510 | clnt->cl_auth = NULL; |
| 486 | kref_put(kref, rpc_free_client); | 511 | if (atomic_dec_and_test(&clnt->cl_count)) |
| 512 | rpc_free_client(clnt); | ||
| 487 | } | 513 | } |
| 488 | 514 | ||
| 489 | /* | 515 | /* |
| @@ -496,7 +522,8 @@ rpc_release_client(struct rpc_clnt *clnt) | |||
| 496 | 522 | ||
| 497 | if (list_empty(&clnt->cl_tasks)) | 523 | if (list_empty(&clnt->cl_tasks)) |
| 498 | wake_up(&destroy_wait); | 524 | wake_up(&destroy_wait); |
| 499 | kref_put(&clnt->cl_kref, rpc_free_auth); | 525 | if (atomic_dec_and_test(&clnt->cl_count)) |
| 526 | rpc_free_auth(clnt); | ||
| 500 | } | 527 | } |
| 501 | 528 | ||
| 502 | /** | 529 | /** |
| @@ -538,6 +565,49 @@ out: | |||
| 538 | } | 565 | } |
| 539 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); | 566 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); |
| 540 | 567 | ||
| 568 | void rpc_task_release_client(struct rpc_task *task) | ||
| 569 | { | ||
| 570 | struct rpc_clnt *clnt = task->tk_client; | ||
| 571 | |||
| 572 | if (clnt != NULL) { | ||
| 573 | /* Remove from client task list */ | ||
| 574 | spin_lock(&clnt->cl_lock); | ||
| 575 | list_del(&task->tk_task); | ||
| 576 | spin_unlock(&clnt->cl_lock); | ||
| 577 | task->tk_client = NULL; | ||
| 578 | |||
| 579 | rpc_release_client(clnt); | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 583 | static | ||
| 584 | void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | ||
| 585 | { | ||
| 586 | if (clnt != NULL) { | ||
| 587 | rpc_task_release_client(task); | ||
| 588 | task->tk_client = clnt; | ||
| 589 | atomic_inc(&clnt->cl_count); | ||
| 590 | if (clnt->cl_softrtry) | ||
| 591 | task->tk_flags |= RPC_TASK_SOFT; | ||
| 592 | /* Add to the client's list of all tasks */ | ||
| 593 | spin_lock(&clnt->cl_lock); | ||
| 594 | list_add_tail(&task->tk_task, &clnt->cl_tasks); | ||
| 595 | spin_unlock(&clnt->cl_lock); | ||
| 596 | } | ||
| 597 | } | ||
| 598 | |||
| 599 | static void | ||
| 600 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) | ||
| 601 | { | ||
| 602 | if (msg != NULL) { | ||
| 603 | task->tk_msg.rpc_proc = msg->rpc_proc; | ||
| 604 | task->tk_msg.rpc_argp = msg->rpc_argp; | ||
| 605 | task->tk_msg.rpc_resp = msg->rpc_resp; | ||
| 606 | if (msg->rpc_cred != NULL) | ||
| 607 | task->tk_msg.rpc_cred = get_rpccred(msg->rpc_cred); | ||
| 608 | } | ||
| 609 | } | ||
| 610 | |||
| 541 | /* | 611 | /* |
| 542 | * Default callback for async RPC calls | 612 | * Default callback for async RPC calls |
| 543 | */ | 613 | */ |
| @@ -556,26 +626,28 @@ static const struct rpc_call_ops rpc_default_ops = { | |||
| 556 | */ | 626 | */ |
| 557 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) | 627 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) |
| 558 | { | 628 | { |
| 559 | struct rpc_task *task, *ret; | 629 | struct rpc_task *task; |
| 560 | 630 | ||
| 561 | task = rpc_new_task(task_setup_data); | 631 | task = rpc_new_task(task_setup_data); |
| 562 | if (task == NULL) { | 632 | if (IS_ERR(task)) |
| 563 | rpc_release_calldata(task_setup_data->callback_ops, | ||
| 564 | task_setup_data->callback_data); | ||
| 565 | ret = ERR_PTR(-ENOMEM); | ||
| 566 | goto out; | 633 | goto out; |
| 567 | } | 634 | |
| 635 | rpc_task_set_client(task, task_setup_data->rpc_client); | ||
| 636 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); | ||
| 568 | 637 | ||
| 569 | if (task->tk_status != 0) { | 638 | if (task->tk_status != 0) { |
| 570 | ret = ERR_PTR(task->tk_status); | 639 | int ret = task->tk_status; |
| 571 | rpc_put_task(task); | 640 | rpc_put_task(task); |
| 572 | goto out; | 641 | return ERR_PTR(ret); |
| 573 | } | 642 | } |
| 643 | |||
| 644 | if (task->tk_action == NULL) | ||
| 645 | rpc_call_start(task); | ||
| 646 | |||
| 574 | atomic_inc(&task->tk_count); | 647 | atomic_inc(&task->tk_count); |
| 575 | rpc_execute(task); | 648 | rpc_execute(task); |
| 576 | ret = task; | ||
| 577 | out: | 649 | out: |
| 578 | return ret; | 650 | return task; |
| 579 | } | 651 | } |
| 580 | EXPORT_SYMBOL_GPL(rpc_run_task); | 652 | EXPORT_SYMBOL_GPL(rpc_run_task); |
| 581 | 653 | ||
| @@ -657,7 +729,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | |||
| 657 | * Create an rpc_task to send the data | 729 | * Create an rpc_task to send the data |
| 658 | */ | 730 | */ |
| 659 | task = rpc_new_task(&task_setup_data); | 731 | task = rpc_new_task(&task_setup_data); |
| 660 | if (!task) { | 732 | if (IS_ERR(task)) { |
| 661 | xprt_free_bc_request(req); | 733 | xprt_free_bc_request(req); |
| 662 | goto out; | 734 | goto out; |
| 663 | } | 735 | } |
| @@ -766,12 +838,13 @@ EXPORT_SYMBOL_GPL(rpc_force_rebind); | |||
| 766 | * Restart an (async) RPC call from the call_prepare state. | 838 | * Restart an (async) RPC call from the call_prepare state. |
| 767 | * Usually called from within the exit handler. | 839 | * Usually called from within the exit handler. |
| 768 | */ | 840 | */ |
| 769 | void | 841 | int |
| 770 | rpc_restart_call_prepare(struct rpc_task *task) | 842 | rpc_restart_call_prepare(struct rpc_task *task) |
| 771 | { | 843 | { |
| 772 | if (RPC_ASSASSINATED(task)) | 844 | if (RPC_ASSASSINATED(task)) |
| 773 | return; | 845 | return 0; |
| 774 | task->tk_action = rpc_prepare_task; | 846 | task->tk_action = rpc_prepare_task; |
| 847 | return 1; | ||
| 775 | } | 848 | } |
| 776 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | 849 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); |
| 777 | 850 | ||
| @@ -779,13 +852,13 @@ EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | |||
| 779 | * Restart an (async) RPC call. Usually called from within the | 852 | * Restart an (async) RPC call. Usually called from within the |
| 780 | * exit handler. | 853 | * exit handler. |
| 781 | */ | 854 | */ |
| 782 | void | 855 | int |
| 783 | rpc_restart_call(struct rpc_task *task) | 856 | rpc_restart_call(struct rpc_task *task) |
| 784 | { | 857 | { |
| 785 | if (RPC_ASSASSINATED(task)) | 858 | if (RPC_ASSASSINATED(task)) |
| 786 | return; | 859 | return 0; |
| 787 | |||
| 788 | task->tk_action = call_start; | 860 | task->tk_action = call_start; |
| 861 | return 1; | ||
| 789 | } | 862 | } |
| 790 | EXPORT_SYMBOL_GPL(rpc_restart_call); | 863 | EXPORT_SYMBOL_GPL(rpc_restart_call); |
| 791 | 864 | ||
| @@ -834,11 +907,6 @@ call_reserve(struct rpc_task *task) | |||
| 834 | { | 907 | { |
| 835 | dprint_status(task); | 908 | dprint_status(task); |
| 836 | 909 | ||
| 837 | if (!rpcauth_uptodatecred(task)) { | ||
| 838 | task->tk_action = call_refresh; | ||
| 839 | return; | ||
| 840 | } | ||
| 841 | |||
| 842 | task->tk_status = 0; | 910 | task->tk_status = 0; |
| 843 | task->tk_action = call_reserveresult; | 911 | task->tk_action = call_reserveresult; |
| 844 | xprt_reserve(task); | 912 | xprt_reserve(task); |
| @@ -861,7 +929,7 @@ call_reserveresult(struct rpc_task *task) | |||
| 861 | task->tk_status = 0; | 929 | task->tk_status = 0; |
| 862 | if (status >= 0) { | 930 | if (status >= 0) { |
| 863 | if (task->tk_rqstp) { | 931 | if (task->tk_rqstp) { |
| 864 | task->tk_action = call_allocate; | 932 | task->tk_action = call_refresh; |
| 865 | return; | 933 | return; |
| 866 | } | 934 | } |
| 867 | 935 | ||
| @@ -896,13 +964,54 @@ call_reserveresult(struct rpc_task *task) | |||
| 896 | } | 964 | } |
| 897 | 965 | ||
| 898 | /* | 966 | /* |
| 899 | * 2. Allocate the buffer. For details, see sched.c:rpc_malloc. | 967 | * 2. Bind and/or refresh the credentials |
| 968 | */ | ||
| 969 | static void | ||
| 970 | call_refresh(struct rpc_task *task) | ||
| 971 | { | ||
| 972 | dprint_status(task); | ||
| 973 | |||
| 974 | task->tk_action = call_refreshresult; | ||
| 975 | task->tk_status = 0; | ||
| 976 | task->tk_client->cl_stats->rpcauthrefresh++; | ||
| 977 | rpcauth_refreshcred(task); | ||
| 978 | } | ||
| 979 | |||
| 980 | /* | ||
| 981 | * 2a. Process the results of a credential refresh | ||
| 982 | */ | ||
| 983 | static void | ||
| 984 | call_refreshresult(struct rpc_task *task) | ||
| 985 | { | ||
| 986 | int status = task->tk_status; | ||
| 987 | |||
| 988 | dprint_status(task); | ||
| 989 | |||
| 990 | task->tk_status = 0; | ||
| 991 | task->tk_action = call_allocate; | ||
| 992 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
| 993 | return; | ||
| 994 | switch (status) { | ||
| 995 | case -EACCES: | ||
| 996 | rpc_exit(task, -EACCES); | ||
| 997 | return; | ||
| 998 | case -ENOMEM: | ||
| 999 | rpc_exit(task, -ENOMEM); | ||
| 1000 | return; | ||
| 1001 | case -ETIMEDOUT: | ||
| 1002 | rpc_delay(task, 3*HZ); | ||
| 1003 | } | ||
| 1004 | task->tk_action = call_refresh; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /* | ||
| 1008 | * 2b. Allocate the buffer. For details, see sched.c:rpc_malloc. | ||
| 900 | * (Note: buffer memory is freed in xprt_release). | 1009 | * (Note: buffer memory is freed in xprt_release). |
| 901 | */ | 1010 | */ |
| 902 | static void | 1011 | static void |
| 903 | call_allocate(struct rpc_task *task) | 1012 | call_allocate(struct rpc_task *task) |
| 904 | { | 1013 | { |
| 905 | unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack; | 1014 | unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack; |
| 906 | struct rpc_rqst *req = task->tk_rqstp; | 1015 | struct rpc_rqst *req = task->tk_rqstp; |
| 907 | struct rpc_xprt *xprt = task->tk_xprt; | 1016 | struct rpc_xprt *xprt = task->tk_xprt; |
| 908 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; | 1017 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; |
| @@ -1482,44 +1591,6 @@ out_retry: | |||
| 1482 | } | 1591 | } |
| 1483 | } | 1592 | } |
| 1484 | 1593 | ||
| 1485 | /* | ||
| 1486 | * 8. Refresh the credentials if rejected by the server | ||
| 1487 | */ | ||
| 1488 | static void | ||
| 1489 | call_refresh(struct rpc_task *task) | ||
| 1490 | { | ||
| 1491 | dprint_status(task); | ||
| 1492 | |||
| 1493 | task->tk_action = call_refreshresult; | ||
| 1494 | task->tk_status = 0; | ||
| 1495 | task->tk_client->cl_stats->rpcauthrefresh++; | ||
| 1496 | rpcauth_refreshcred(task); | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | /* | ||
| 1500 | * 8a. Process the results of a credential refresh | ||
| 1501 | */ | ||
| 1502 | static void | ||
| 1503 | call_refreshresult(struct rpc_task *task) | ||
| 1504 | { | ||
| 1505 | int status = task->tk_status; | ||
| 1506 | |||
| 1507 | dprint_status(task); | ||
| 1508 | |||
| 1509 | task->tk_status = 0; | ||
| 1510 | task->tk_action = call_reserve; | ||
| 1511 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
| 1512 | return; | ||
| 1513 | if (status == -EACCES) { | ||
| 1514 | rpc_exit(task, -EACCES); | ||
| 1515 | return; | ||
| 1516 | } | ||
| 1517 | task->tk_action = call_refresh; | ||
| 1518 | if (status != -ETIMEDOUT) | ||
| 1519 | rpc_delay(task, 3*HZ); | ||
| 1520 | return; | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | static __be32 * | 1594 | static __be32 * |
| 1524 | rpc_encode_header(struct rpc_task *task) | 1595 | rpc_encode_header(struct rpc_task *task) |
| 1525 | { | 1596 | { |
