|
@@ -2492,7 +2492,10 @@ static int rpc_ping(struct rpc_clnt *clnt)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
|
|
|
+static
|
|
|
+struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
|
|
|
+ struct rpc_xprt *xprt, struct rpc_cred *cred, int flags,
|
|
|
+ const struct rpc_call_ops *ops, void *data)
|
|
|
{
|
|
|
struct rpc_message msg = {
|
|
|
.rpc_proc = &rpcproc_null,
|
|
@@ -2500,14 +2503,140 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int
|
|
|
};
|
|
|
struct rpc_task_setup task_setup_data = {
|
|
|
.rpc_client = clnt,
|
|
|
+ .rpc_xprt = xprt,
|
|
|
.rpc_message = &msg,
|
|
|
- .callback_ops = &rpc_default_ops,
|
|
|
+ .callback_ops = (ops != NULL) ? ops : &rpc_default_ops,
|
|
|
+ .callback_data = data,
|
|
|
.flags = flags,
|
|
|
};
|
|
|
+
|
|
|
return rpc_run_task(&task_setup_data);
|
|
|
}
|
|
|
+
|
|
|
+struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
|
|
|
+{
|
|
|
+ return rpc_call_null_helper(clnt, NULL, cred, flags, NULL, NULL);
|
|
|
+}
|
|
|
EXPORT_SYMBOL_GPL(rpc_call_null);
|
|
|
|
|
|
+struct rpc_cb_add_xprt_calldata {
|
|
|
+ struct rpc_xprt_switch *xps;
|
|
|
+ struct rpc_xprt *xprt;
|
|
|
+};
|
|
|
+
|
|
|
+static void rpc_cb_add_xprt_done(struct rpc_task *task, void *calldata)
|
|
|
+{
|
|
|
+ struct rpc_cb_add_xprt_calldata *data = calldata;
|
|
|
+
|
|
|
+ if (task->tk_status == 0)
|
|
|
+ rpc_xprt_switch_add_xprt(data->xps, data->xprt);
|
|
|
+}
|
|
|
+
|
|
|
+static void rpc_cb_add_xprt_release(void *calldata)
|
|
|
+{
|
|
|
+ struct rpc_cb_add_xprt_calldata *data = calldata;
|
|
|
+
|
|
|
+ xprt_put(data->xprt);
|
|
|
+ xprt_switch_put(data->xps);
|
|
|
+ kfree(data);
|
|
|
+}
|
|
|
+
|
|
|
+const static struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
|
|
|
+ .rpc_call_done = rpc_cb_add_xprt_done,
|
|
|
+ .rpc_release = rpc_cb_add_xprt_release,
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * rpc_clnt_test_and_add_xprt - Test and add a new transport to a rpc_clnt
|
|
|
+ * @clnt: pointer to struct rpc_clnt
|
|
|
+ * @xps: pointer to struct rpc_xprt_switch,
|
|
|
+ * @xprt: pointer struct rpc_xprt
|
|
|
+ * @dummy: unused
|
|
|
+ */
|
|
|
+int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
|
|
|
+ struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
|
|
|
+ void *dummy)
|
|
|
+{
|
|
|
+ struct rpc_cb_add_xprt_calldata *data;
|
|
|
+ struct rpc_cred *cred;
|
|
|
+ struct rpc_task *task;
|
|
|
+
|
|
|
+ data = kmalloc(sizeof(*data), GFP_NOFS);
|
|
|
+ if (!data)
|
|
|
+ return -ENOMEM;
|
|
|
+ data->xps = xprt_switch_get(xps);
|
|
|
+ data->xprt = xprt_get(xprt);
|
|
|
+
|
|
|
+ cred = authnull_ops.lookup_cred(NULL, NULL, 0);
|
|
|
+ task = rpc_call_null_helper(clnt, xprt, cred,
|
|
|
+ RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC,
|
|
|
+ &rpc_cb_add_xprt_call_ops, data);
|
|
|
+ put_rpccred(cred);
|
|
|
+ if (IS_ERR(task))
|
|
|
+ return PTR_ERR(task);
|
|
|
+ rpc_put_task(task);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
|
|
|
+
|
|
|
+/**
|
|
|
+ * rpc_clnt_add_xprt - Add a new transport to a rpc_clnt
|
|
|
+ * @clnt: pointer to struct rpc_clnt
|
|
|
+ * @xprtargs: pointer to struct xprt_create
|
|
|
+ * @setup: callback to test and/or set up the connection
|
|
|
+ * @data: pointer to setup function data
|
|
|
+ *
|
|
|
+ * Creates a new transport using the parameters set in args and
|
|
|
+ * adds it to clnt.
|
|
|
+ * If ping is set, then test that connectivity succeeds before
|
|
|
+ * adding the new transport.
|
|
|
+ *
|
|
|
+ */
|
|
|
+int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
|
|
|
+ struct xprt_create *xprtargs,
|
|
|
+ int (*setup)(struct rpc_clnt *,
|
|
|
+ struct rpc_xprt_switch *,
|
|
|
+ struct rpc_xprt *,
|
|
|
+ void *),
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct rpc_xprt_switch *xps;
|
|
|
+ struct rpc_xprt *xprt;
|
|
|
+ unsigned char resvport;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
|
|
|
+ xprt = xprt_iter_xprt(&clnt->cl_xpi);
|
|
|
+ if (xps == NULL || xprt == NULL) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+ resvport = xprt->resvport;
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
+ xprt = xprt_create_transport(xprtargs);
|
|
|
+ if (IS_ERR(xprt)) {
|
|
|
+ ret = PTR_ERR(xprt);
|
|
|
+ goto out_put_switch;
|
|
|
+ }
|
|
|
+ xprt->resvport = resvport;
|
|
|
+
|
|
|
+ rpc_xprt_switch_set_roundrobin(xps);
|
|
|
+ if (setup) {
|
|
|
+ ret = setup(clnt, xps, xprt, data);
|
|
|
+ if (ret != 0)
|
|
|
+ goto out_put_xprt;
|
|
|
+ }
|
|
|
+ rpc_xprt_switch_add_xprt(xps, xprt);
|
|
|
+out_put_xprt:
|
|
|
+ xprt_put(xprt);
|
|
|
+out_put_switch:
|
|
|
+ xprt_switch_put(xps);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
|
|
|
+
|
|
|
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
|
|
static void rpc_show_header(void)
|
|
|
{
|