diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
| -rw-r--r-- | net/sunrpc/xprtsock.c | 43 | 
1 files changed, 28 insertions, 15 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e193c2b5476b..7be90bc1a7c2 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -527,6 +527,10 @@ static int xs_local_send_request(struct rpc_task *task)  			      true, &sent);  	dprintk("RPC:       %s(%u) = %d\n",  			__func__, xdr->len - req->rq_bytes_sent, status); + +	if (status == -EAGAIN && sock_writeable(transport->inet)) +		status = -ENOBUFS; +  	if (likely(sent > 0) || status == 0) {  		req->rq_bytes_sent += sent;  		req->rq_xmit_bytes_sent += sent; @@ -539,6 +543,7 @@ static int xs_local_send_request(struct rpc_task *task)  	switch (status) {  	case -ENOBUFS: +		break;  	case -EAGAIN:  		status = xs_nospace(task);  		break; @@ -589,6 +594,9 @@ static int xs_udp_send_request(struct rpc_task *task)  	if (status == -EPERM)  		goto process_status; +	if (status == -EAGAIN && sock_writeable(transport->inet)) +		status = -ENOBUFS; +  	if (sent > 0 || status == 0) {  		req->rq_xmit_bytes_sent += sent;  		if (sent >= req->rq_slen) @@ -669,9 +677,6 @@ static int xs_tcp_send_request(struct rpc_task *task)  		dprintk("RPC:       xs_tcp_send_request(%u) = %d\n",  				xdr->len - req->rq_bytes_sent, status); -		if (unlikely(sent == 0 && status < 0)) -			break; -  		/* If we've sent the entire packet, immediately  		 * reset the count of bytes sent. */  		req->rq_bytes_sent += sent; @@ -681,18 +686,21 @@ static int xs_tcp_send_request(struct rpc_task *task)  			return 0;  		} -		if (sent != 0) -			continue; -		status = -EAGAIN; -		break; +		if (status < 0) +			break; +		if (sent == 0) { +			status = -EAGAIN; +			break; +		}  	} +	if (status == -EAGAIN && sk_stream_is_writeable(transport->inet)) +		status = -ENOBUFS;  	switch (status) {  	case -ENOTSOCK:  		status = -ENOTCONN;  		/* Should we call xs_close() here? */  		break; -	case -ENOBUFS:  	case -EAGAIN:  		status = xs_nospace(task);  		break; @@ -703,6 +711,7 @@ static int xs_tcp_send_request(struct rpc_task *task)  	case -ECONNREFUSED:  	case -ENOTCONN:  	case -EADDRINUSE: +	case -ENOBUFS:  	case -EPIPE:  		clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);  	} @@ -813,6 +822,8 @@ static void xs_reset_transport(struct sock_xprt *transport)  	if (atomic_read(&transport->xprt.swapper))  		sk_clear_memalloc(sk); +	kernel_sock_shutdown(sock, SHUT_RDWR); +  	write_lock_bh(&sk->sk_callback_lock);  	transport->inet = NULL;  	transport->sock = NULL; @@ -820,6 +831,7 @@ static void xs_reset_transport(struct sock_xprt *transport)  	sk->sk_user_data = NULL;  	xs_restore_old_callbacks(transport, sk); +	xprt_clear_connected(xprt);  	write_unlock_bh(&sk->sk_callback_lock);  	xs_sock_reset_connection_flags(xprt); @@ -1857,7 +1869,7 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,  		sk->sk_data_ready = xs_local_data_ready;  		sk->sk_write_space = xs_udp_write_space;  		sk->sk_error_report = xs_error_report; -		sk->sk_allocation = GFP_ATOMIC; +		sk->sk_allocation = GFP_NOIO;  		xprt_clear_connected(xprt); @@ -2042,7 +2054,7 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)  		sk->sk_user_data = xprt;  		sk->sk_data_ready = xs_udp_data_ready;  		sk->sk_write_space = xs_udp_write_space; -		sk->sk_allocation = GFP_ATOMIC; +		sk->sk_allocation = GFP_NOIO;  		xprt_set_connected(xprt); @@ -2144,7 +2156,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)  		sk->sk_state_change = xs_tcp_state_change;  		sk->sk_write_space = xs_tcp_write_space;  		sk->sk_error_report = xs_error_report; -		sk->sk_allocation = GFP_ATOMIC; +		sk->sk_allocation = GFP_NOIO;  		/* socket options */  		sock_reset_flag(sk, SOCK_LINGER); @@ -2270,13 +2282,14 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)  	WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport)); -	/* Start by resetting any existing state */ -	xs_reset_transport(transport); - -	if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) { +	if (transport->sock != NULL) {  		dprintk("RPC:       xs_connect delayed xprt %p for %lu "  				"seconds\n",  				xprt, xprt->reestablish_timeout / HZ); + +		/* Start by resetting any existing state */ +		xs_reset_transport(transport); +  		queue_delayed_work(rpciod_workqueue,  				   &transport->connect_worker,  				   xprt->reestablish_timeout);  |