diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-01-30 23:43:35 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-02-05 18:48:57 -0500 |
commit | 7f554890587c63ca4c087d6bcc4a9fe368e57484 (patch) | |
tree | 20e402fd717b734eb7c6e6b693863cbc98a4bc3b | |
parent | d9ddbf5d9225a417076e89ef650dd276165dfd07 (diff) |
SUNRPC: Allow addition of new transports to a struct rpc_clnt
Add a function to allow creation and addition of a new transport
to an existing rpc_clnt
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | include/linux/sunrpc/clnt.h | 11 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 133 |
2 files changed, 142 insertions, 2 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index d6510f64a361..9a7ddbaf116e 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -186,6 +186,17 @@ int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt, | |||
186 | int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *), | 186 | int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *), |
187 | void *data); | 187 | void *data); |
188 | 188 | ||
189 | int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, | ||
190 | struct rpc_xprt_switch *xps, | ||
191 | struct rpc_xprt *xprt, | ||
192 | void *dummy); | ||
193 | int rpc_clnt_add_xprt(struct rpc_clnt *, struct xprt_create *, | ||
194 | int (*setup)(struct rpc_clnt *, | ||
195 | struct rpc_xprt_switch *, | ||
196 | struct rpc_xprt *, | ||
197 | void *), | ||
198 | void *data); | ||
199 | |||
189 | const char *rpc_proc_name(const struct rpc_task *task); | 200 | const char *rpc_proc_name(const struct rpc_task *task); |
190 | #endif /* __KERNEL__ */ | 201 | #endif /* __KERNEL__ */ |
191 | #endif /* _LINUX_SUNRPC_CLNT_H */ | 202 | #endif /* _LINUX_SUNRPC_CLNT_H */ |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4b6ceb7c5e1d..7e0c9bf22df8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -2492,7 +2492,10 @@ static int rpc_ping(struct rpc_clnt *clnt) | |||
2492 | return err; | 2492 | return err; |
2493 | } | 2493 | } |
2494 | 2494 | ||
2495 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags) | 2495 | static |
2496 | struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt, | ||
2497 | struct rpc_xprt *xprt, struct rpc_cred *cred, int flags, | ||
2498 | const struct rpc_call_ops *ops, void *data) | ||
2496 | { | 2499 | { |
2497 | struct rpc_message msg = { | 2500 | struct rpc_message msg = { |
2498 | .rpc_proc = &rpcproc_null, | 2501 | .rpc_proc = &rpcproc_null, |
@@ -2500,14 +2503,140 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int | |||
2500 | }; | 2503 | }; |
2501 | struct rpc_task_setup task_setup_data = { | 2504 | struct rpc_task_setup task_setup_data = { |
2502 | .rpc_client = clnt, | 2505 | .rpc_client = clnt, |
2506 | .rpc_xprt = xprt, | ||
2503 | .rpc_message = &msg, | 2507 | .rpc_message = &msg, |
2504 | .callback_ops = &rpc_default_ops, | 2508 | .callback_ops = (ops != NULL) ? ops : &rpc_default_ops, |
2509 | .callback_data = data, | ||
2505 | .flags = flags, | 2510 | .flags = flags, |
2506 | }; | 2511 | }; |
2512 | |||
2507 | return rpc_run_task(&task_setup_data); | 2513 | return rpc_run_task(&task_setup_data); |
2508 | } | 2514 | } |
2515 | |||
2516 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags) | ||
2517 | { | ||
2518 | return rpc_call_null_helper(clnt, NULL, cred, flags, NULL, NULL); | ||
2519 | } | ||
2509 | EXPORT_SYMBOL_GPL(rpc_call_null); | 2520 | EXPORT_SYMBOL_GPL(rpc_call_null); |
2510 | 2521 | ||
2522 | struct rpc_cb_add_xprt_calldata { | ||
2523 | struct rpc_xprt_switch *xps; | ||
2524 | struct rpc_xprt *xprt; | ||
2525 | }; | ||
2526 | |||
2527 | static void rpc_cb_add_xprt_done(struct rpc_task *task, void *calldata) | ||
2528 | { | ||
2529 | struct rpc_cb_add_xprt_calldata *data = calldata; | ||
2530 | |||
2531 | if (task->tk_status == 0) | ||
2532 | rpc_xprt_switch_add_xprt(data->xps, data->xprt); | ||
2533 | } | ||
2534 | |||
2535 | static void rpc_cb_add_xprt_release(void *calldata) | ||
2536 | { | ||
2537 | struct rpc_cb_add_xprt_calldata *data = calldata; | ||
2538 | |||
2539 | xprt_put(data->xprt); | ||
2540 | xprt_switch_put(data->xps); | ||
2541 | kfree(data); | ||
2542 | } | ||
2543 | |||
2544 | const static struct rpc_call_ops rpc_cb_add_xprt_call_ops = { | ||
2545 | .rpc_call_done = rpc_cb_add_xprt_done, | ||
2546 | .rpc_release = rpc_cb_add_xprt_release, | ||
2547 | }; | ||
2548 | |||
2549 | /** | ||
2550 | * rpc_clnt_test_and_add_xprt - Test and add a new transport to a rpc_clnt | ||
2551 | * @clnt: pointer to struct rpc_clnt | ||
2552 | * @xps: pointer to struct rpc_xprt_switch, | ||
2553 | * @xprt: pointer struct rpc_xprt | ||
2554 | * @dummy: unused | ||
2555 | */ | ||
2556 | int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, | ||
2557 | struct rpc_xprt_switch *xps, struct rpc_xprt *xprt, | ||
2558 | void *dummy) | ||
2559 | { | ||
2560 | struct rpc_cb_add_xprt_calldata *data; | ||
2561 | struct rpc_cred *cred; | ||
2562 | struct rpc_task *task; | ||
2563 | |||
2564 | data = kmalloc(sizeof(*data), GFP_NOFS); | ||
2565 | if (!data) | ||
2566 | return -ENOMEM; | ||
2567 | data->xps = xprt_switch_get(xps); | ||
2568 | data->xprt = xprt_get(xprt); | ||
2569 | |||
2570 | cred = authnull_ops.lookup_cred(NULL, NULL, 0); | ||
2571 | task = rpc_call_null_helper(clnt, xprt, cred, | ||
2572 | RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC, | ||
2573 | &rpc_cb_add_xprt_call_ops, data); | ||
2574 | put_rpccred(cred); | ||
2575 | if (IS_ERR(task)) | ||
2576 | return PTR_ERR(task); | ||
2577 | rpc_put_task(task); | ||
2578 | return 1; | ||
2579 | } | ||
2580 | EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt); | ||
2581 | |||
2582 | /** | ||
2583 | * rpc_clnt_add_xprt - Add a new transport to a rpc_clnt | ||
2584 | * @clnt: pointer to struct rpc_clnt | ||
2585 | * @xprtargs: pointer to struct xprt_create | ||
2586 | * @setup: callback to test and/or set up the connection | ||
2587 | * @data: pointer to setup function data | ||
2588 | * | ||
2589 | * Creates a new transport using the parameters set in args and | ||
2590 | * adds it to clnt. | ||
2591 | * If ping is set, then test that connectivity succeeds before | ||
2592 | * adding the new transport. | ||
2593 | * | ||
2594 | */ | ||
2595 | int rpc_clnt_add_xprt(struct rpc_clnt *clnt, | ||
2596 | struct xprt_create *xprtargs, | ||
2597 | int (*setup)(struct rpc_clnt *, | ||
2598 | struct rpc_xprt_switch *, | ||
2599 | struct rpc_xprt *, | ||
2600 | void *), | ||
2601 | void *data) | ||
2602 | { | ||
2603 | struct rpc_xprt_switch *xps; | ||
2604 | struct rpc_xprt *xprt; | ||
2605 | unsigned char resvport; | ||
2606 | int ret = 0; | ||
2607 | |||
2608 | rcu_read_lock(); | ||
2609 | xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch)); | ||
2610 | xprt = xprt_iter_xprt(&clnt->cl_xpi); | ||
2611 | if (xps == NULL || xprt == NULL) { | ||
2612 | rcu_read_unlock(); | ||
2613 | return -EAGAIN; | ||
2614 | } | ||
2615 | resvport = xprt->resvport; | ||
2616 | rcu_read_unlock(); | ||
2617 | |||
2618 | xprt = xprt_create_transport(xprtargs); | ||
2619 | if (IS_ERR(xprt)) { | ||
2620 | ret = PTR_ERR(xprt); | ||
2621 | goto out_put_switch; | ||
2622 | } | ||
2623 | xprt->resvport = resvport; | ||
2624 | |||
2625 | rpc_xprt_switch_set_roundrobin(xps); | ||
2626 | if (setup) { | ||
2627 | ret = setup(clnt, xps, xprt, data); | ||
2628 | if (ret != 0) | ||
2629 | goto out_put_xprt; | ||
2630 | } | ||
2631 | rpc_xprt_switch_add_xprt(xps, xprt); | ||
2632 | out_put_xprt: | ||
2633 | xprt_put(xprt); | ||
2634 | out_put_switch: | ||
2635 | xprt_switch_put(xps); | ||
2636 | return ret; | ||
2637 | } | ||
2638 | EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt); | ||
2639 | |||
2511 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) | 2640 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
2512 | static void rpc_show_header(void) | 2641 | static void rpc_show_header(void) |
2513 | { | 2642 | { |