aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-01-30 23:43:35 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2016-02-05 18:48:57 -0500
commit7f554890587c63ca4c087d6bcc4a9fe368e57484 (patch)
tree20e402fd717b734eb7c6e6b693863cbc98a4bc3b
parentd9ddbf5d9225a417076e89ef650dd276165dfd07 (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.h11
-rw-r--r--net/sunrpc/clnt.c133
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
189int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
190 struct rpc_xprt_switch *xps,
191 struct rpc_xprt *xprt,
192 void *dummy);
193int 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
189const char *rpc_proc_name(const struct rpc_task *task); 200const 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
2495struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags) 2495static
2496struct 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
2516struct 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}
2509EXPORT_SYMBOL_GPL(rpc_call_null); 2520EXPORT_SYMBOL_GPL(rpc_call_null);
2510 2521
2522struct rpc_cb_add_xprt_calldata {
2523 struct rpc_xprt_switch *xps;
2524 struct rpc_xprt *xprt;
2525};
2526
2527static 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
2535static 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
2544const 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 */
2556int 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}
2580EXPORT_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 */
2595int 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);
2632out_put_xprt:
2633 xprt_put(xprt);
2634out_put_switch:
2635 xprt_switch_put(xps);
2636 return ret;
2637}
2638EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
2639
2511#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 2640#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
2512static void rpc_show_header(void) 2641static void rpc_show_header(void)
2513{ 2642{