net/sunrpc/clnt.c

Source file repositories/reference/linux-study-clean/net/sunrpc/clnt.c

File Facts

System
Linux kernel
Corpus path
net/sunrpc/clnt.c
Extension
.c
Size
82860 bytes
Lines
3426
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

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);
}

static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
	.rpc_call_prepare = rpc_null_call_prepare,
	.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
 * @in_max_connect: pointer to the max_connect value for the passed in xprt transport
 */
int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
		struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
		void *in_max_connect)
{
	struct rpc_cb_add_xprt_calldata *data;
	struct rpc_task *task;
	int max_connect = clnt->cl_max_connect;

	if (in_max_connect)
		max_connect = *(int *)in_max_connect;
	if (xps->xps_nunique_destaddr_xprts + 1 > max_connect) {
		rcu_read_lock();
		pr_warn("SUNRPC: reached max allowed number (%d) did not add "
			"transport to server: %s\n", max_connect,
			rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
		rcu_read_unlock();
		return -EINVAL;
	}

	data = kmalloc_obj(*data);
	if (!data)
		return -ENOMEM;
	data->xps = xprt_switch_get(xps);
	data->xprt = xprt_get(xprt);
	if (rpc_xprt_switch_has_addr(data->xps, (struct sockaddr *)&xprt->addr)) {
		rpc_cb_add_xprt_release(data);
		goto success;
	}

	task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC,
			&rpc_cb_add_xprt_call_ops, data);
	if (IS_ERR(task))
		return PTR_ERR(task);

	data->xps->xps_nunique_destaddr_xprts++;
	rpc_put_task(task);
success:
	return 1;
}
EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);

static int rpc_clnt_add_xprt_helper(struct rpc_clnt *clnt,
				    struct rpc_xprt *xprt,
				    struct rpc_add_xprt_test *data)
{
	struct rpc_task *task;
	int status = -EADDRINUSE;

	/* Test the connection */
	task = rpc_call_null_helper(clnt, xprt, NULL, 0, NULL, NULL);
	if (IS_ERR(task))
		return PTR_ERR(task);

	status = task->tk_status;
	rpc_put_task(task);

Annotation

Implementation Notes