diff options
Diffstat (limited to 'net/sunrpc/clnt.c')
| -rw-r--r-- | net/sunrpc/clnt.c | 109 | 
1 files changed, 84 insertions, 25 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e6ce1517367f..cbc6af923dd1 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -891,15 +891,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)  			task->tk_flags |= RPC_TASK_SOFT;  		if (clnt->cl_noretranstimeo)  			task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; -		if (sk_memalloc_socks()) { -			struct rpc_xprt *xprt; - -			rcu_read_lock(); -			xprt = rcu_dereference(clnt->cl_xprt); -			if (xprt->swapper) -				task->tk_flags |= RPC_TASK_SWAPPER; -			rcu_read_unlock(); -		} +		if (atomic_read(&clnt->cl_swapper)) +			task->tk_flags |= RPC_TASK_SWAPPER;  		/* Add to the client's list of all tasks */  		spin_lock(&clnt->cl_lock);  		list_add_tail(&task->tk_task, &clnt->cl_tasks); @@ -1031,15 +1024,14 @@ EXPORT_SYMBOL_GPL(rpc_call_async);   * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run   * rpc_execute against it   * @req: RPC request - * @tk_ops: RPC call ops   */ -struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, -				const struct rpc_call_ops *tk_ops) +struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)  {  	struct rpc_task *task;  	struct xdr_buf *xbufp = &req->rq_snd_buf;  	struct rpc_task_setup task_setup_data = { -		.callback_ops = tk_ops, +		.callback_ops = &rpc_default_ops, +		.flags = RPC_TASK_SOFTCONN,  	};  	dprintk("RPC: rpc_run_bc_task req= %p\n", req); @@ -1614,6 +1606,7 @@ call_allocate(struct rpc_task *task)  					req->rq_callsize + req->rq_rcvsize);  	if (req->rq_buffer != NULL)  		return; +	xprt_inject_disconnect(xprt);  	dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid); @@ -1951,33 +1944,36 @@ call_bc_transmit(struct rpc_task *task)  {  	struct rpc_rqst *req = task->tk_rqstp; -	if (!xprt_prepare_transmit(task)) { -		/* -		 * Could not reserve the transport. Try again after the -		 * transport is released. -		 */ -		task->tk_status = 0; -		task->tk_action = call_bc_transmit; -		return; -	} +	if (!xprt_prepare_transmit(task)) +		goto out_retry; -	task->tk_action = rpc_exit_task;  	if (task->tk_status < 0) {  		printk(KERN_NOTICE "RPC: Could not send backchannel reply "  			"error: %d\n", task->tk_status); -		return; +		goto out_done;  	} +	if (req->rq_connect_cookie != req->rq_xprt->connect_cookie) +		req->rq_bytes_sent = 0;  	xprt_transmit(task); + +	if (task->tk_status == -EAGAIN) +		goto out_nospace; +  	xprt_end_transmit(task);  	dprint_status(task);  	switch (task->tk_status) {  	case 0:  		/* Success */ -		break;  	case -EHOSTDOWN:  	case -EHOSTUNREACH:  	case -ENETUNREACH: +	case -ECONNRESET: +	case -ECONNREFUSED: +	case -EADDRINUSE: +	case -ENOTCONN: +	case -EPIPE: +		break;  	case -ETIMEDOUT:  		/*  		 * Problem reaching the server.  Disconnect and let the @@ -2002,6 +1998,13 @@ call_bc_transmit(struct rpc_task *task)  		break;  	}  	rpc_wake_up_queued_task(&req->rq_xprt->pending, task); +out_done: +	task->tk_action = rpc_exit_task; +	return; +out_nospace: +	req->rq_connect_cookie = req->rq_xprt->connect_cookie; +out_retry: +	task->tk_status = 0;  }  #endif /* CONFIG_SUNRPC_BACKCHANNEL */ @@ -2476,3 +2479,59 @@ void rpc_show_tasks(struct net *net)  	spin_unlock(&sn->rpc_client_lock);  }  #endif + +#if IS_ENABLED(CONFIG_SUNRPC_SWAP) +int +rpc_clnt_swap_activate(struct rpc_clnt *clnt) +{ +	int ret = 0; +	struct rpc_xprt	*xprt; + +	if (atomic_inc_return(&clnt->cl_swapper) == 1) { +retry: +		rcu_read_lock(); +		xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); +		rcu_read_unlock(); +		if (!xprt) { +			/* +			 * If we didn't get a reference, then we likely are +			 * racing with a migration event. Wait for a grace +			 * period and try again. +			 */ +			synchronize_rcu(); +			goto retry; +		} + +		ret = xprt_enable_swap(xprt); +		xprt_put(xprt); +	} +	return ret; +} +EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate); + +void +rpc_clnt_swap_deactivate(struct rpc_clnt *clnt) +{ +	struct rpc_xprt	*xprt; + +	if (atomic_dec_if_positive(&clnt->cl_swapper) == 0) { +retry: +		rcu_read_lock(); +		xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); +		rcu_read_unlock(); +		if (!xprt) { +			/* +			 * If we didn't get a reference, then we likely are +			 * racing with a migration event. Wait for a grace +			 * period and try again. +			 */ +			synchronize_rcu(); +			goto retry; +		} + +		xprt_disable_swap(xprt); +		xprt_put(xprt); +	} +} +EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate); +#endif /* CONFIG_SUNRPC_SWAP */  |