diff options
Diffstat (limited to 'net/sunrpc/clnt.c')
| -rw-r--r-- | net/sunrpc/clnt.c | 132 | 
1 files changed, 107 insertions, 25 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 66f23b376fa0..34dd7b26ee5f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -184,7 +184,6 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,  				   struct super_block *sb)  {  	struct dentry *dentry; -	int err = 0;  	switch (event) {  	case RPC_PIPEFS_MOUNT: @@ -201,7 +200,7 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,  		printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);  		return -ENOTSUPP;  	} -	return err; +	return 0;  }  static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, @@ -988,7 +987,6 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)  {  	if (clnt != NULL) { -		rpc_task_release_client(task);  		if (task->tk_xprt == NULL)  			task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi);  		task->tk_client = clnt; @@ -1693,6 +1691,7 @@ call_allocate(struct rpc_task *task)  	struct rpc_rqst *req = task->tk_rqstp;  	struct rpc_xprt *xprt = req->rq_xprt;  	struct rpc_procinfo *proc = task->tk_msg.rpc_proc; +	int status;  	dprint_status(task); @@ -1718,11 +1717,14 @@ call_allocate(struct rpc_task *task)  	req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;  	req->rq_rcvsize <<= 2; -	req->rq_buffer = xprt->ops->buf_alloc(task, -					req->rq_callsize + req->rq_rcvsize); -	if (req->rq_buffer != NULL) -		return; +	status = xprt->ops->buf_alloc(task);  	xprt_inject_disconnect(xprt); +	if (status == 0) +		return; +	if (status != -ENOMEM) { +		rpc_exit(task, status); +		return; +	}  	dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid); @@ -1748,18 +1750,6 @@ rpc_task_force_reencode(struct rpc_task *task)  	task->tk_rqstp->rq_bytes_sent = 0;  } -static inline void -rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) -{ -	buf->head[0].iov_base = start; -	buf->head[0].iov_len = len; -	buf->tail[0].iov_len = 0; -	buf->page_len = 0; -	buf->flags = 0; -	buf->len = 0; -	buf->buflen = len; -} -  /*   * 3.	Encode arguments of an RPC call   */ @@ -1772,12 +1762,12 @@ rpc_xdr_encode(struct rpc_task *task)  	dprint_status(task); -	rpc_xdr_buf_init(&req->rq_snd_buf, -			 req->rq_buffer, -			 req->rq_callsize); -	rpc_xdr_buf_init(&req->rq_rcv_buf, -			 (char *)req->rq_buffer + req->rq_callsize, -			 req->rq_rcvsize); +	xdr_buf_init(&req->rq_snd_buf, +		     req->rq_buffer, +		     req->rq_callsize); +	xdr_buf_init(&req->rq_rcv_buf, +		     req->rq_rbuffer, +		     req->rq_rcvsize);  	p = rpc_encode_header(task);  	if (p == NULL) { @@ -2616,6 +2606,70 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,  EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);  /** + * rpc_clnt_setup_test_and_add_xprt() + * + * This is an rpc_clnt_add_xprt setup() function which returns 1 so: + *   1) caller of the test function must dereference the rpc_xprt_switch + *   and the rpc_xprt. + *   2) test function must call rpc_xprt_switch_add_xprt, usually in + *   the rpc_call_done routine. + * + * Upon success (return of 1), the test function adds the new + * transport to the rpc_clnt xprt switch + * + * @clnt: struct rpc_clnt to get the new transport + * @xps:  the rpc_xprt_switch to hold the new transport + * @xprt: the rpc_xprt to test + * @data: a struct rpc_add_xprt_test pointer that holds the test function + *        and test function call data + */ +int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *clnt, +				     struct rpc_xprt_switch *xps, +				     struct rpc_xprt *xprt, +				     void *data) +{ +	struct rpc_cred *cred; +	struct rpc_task *task; +	struct rpc_add_xprt_test *xtest = (struct rpc_add_xprt_test *)data; +	int status = -EADDRINUSE; + +	xprt = xprt_get(xprt); +	xprt_switch_get(xps); + +	if (rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr)) +		goto out_err; + +	/* Test the connection */ +	cred = authnull_ops.lookup_cred(NULL, NULL, 0); +	task = rpc_call_null_helper(clnt, xprt, cred, +				    RPC_TASK_SOFT | RPC_TASK_SOFTCONN, +				    NULL, NULL); +	put_rpccred(cred); +	if (IS_ERR(task)) { +		status = PTR_ERR(task); +		goto out_err; +	} +	status = task->tk_status; +	rpc_put_task(task); + +	if (status < 0) +		goto out_err; + +	/* rpc_xprt_switch and rpc_xprt are deferrenced by add_xprt_test() */ +	xtest->add_xprt_test(clnt, xprt, xtest->data); + +	/* so that rpc_clnt_add_xprt does not call rpc_xprt_switch_add_xprt */ +	return 1; +out_err: +	xprt_put(xprt); +	xprt_switch_put(xps); +	pr_info("RPC:   rpc_clnt_test_xprt failed: %d addr %s not added\n", +		status, xprt->address_strings[RPC_DISPLAY_ADDR]); +	return status; +} +EXPORT_SYMBOL_GPL(rpc_clnt_setup_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 @@ -2697,6 +2751,34 @@ rpc_cap_max_reconnect_timeout(struct rpc_clnt *clnt, unsigned long timeo)  }  EXPORT_SYMBOL_GPL(rpc_cap_max_reconnect_timeout); +void rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt) +{ +	xprt_switch_put(rcu_dereference(clnt->cl_xpi.xpi_xpswitch)); +} +EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_put); + +void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt) +{ +	rpc_xprt_switch_add_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch), +				 xprt); +} +EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_add_xprt); + +bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt, +				   const struct sockaddr *sap) +{ +	struct rpc_xprt_switch *xps; +	bool ret; + +	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch); + +	rcu_read_lock(); +	ret = rpc_xprt_switch_has_addr(xps, sap); +	rcu_read_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_has_addr); +  #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)  static void rpc_show_header(void)  {  |