mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-03 07:38:10 +00:00
SUNRPC: Fix socket waits for write buffer space
The socket layer requires that we use the socket lock to protect changes to the sock->sk_write_pending field and others. Reported-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
3b21f757c3
commit
7496b59f58
1 changed files with 42 additions and 18 deletions
|
@ -764,12 +764,12 @@ xs_stream_start_connect(struct sock_xprt *transport)
|
||||||
/**
|
/**
|
||||||
* xs_nospace - handle transmit was incomplete
|
* xs_nospace - handle transmit was incomplete
|
||||||
* @req: pointer to RPC request
|
* @req: pointer to RPC request
|
||||||
|
* @transport: pointer to struct sock_xprt
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int xs_nospace(struct rpc_rqst *req)
|
static int xs_nospace(struct rpc_rqst *req, struct sock_xprt *transport)
|
||||||
{
|
{
|
||||||
struct rpc_xprt *xprt = req->rq_xprt;
|
struct rpc_xprt *xprt = &transport->xprt;
|
||||||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
|
||||||
struct sock *sk = transport->inet;
|
struct sock *sk = transport->inet;
|
||||||
int ret = -EAGAIN;
|
int ret = -EAGAIN;
|
||||||
|
|
||||||
|
@ -780,16 +780,6 @@ static int xs_nospace(struct rpc_rqst *req)
|
||||||
|
|
||||||
/* Don't race with disconnect */
|
/* Don't race with disconnect */
|
||||||
if (xprt_connected(xprt)) {
|
if (xprt_connected(xprt)) {
|
||||||
/* wait for more buffer space */
|
|
||||||
sk->sk_write_pending++;
|
|
||||||
xprt_wait_for_buffer_space(xprt);
|
|
||||||
} else
|
|
||||||
ret = -ENOTCONN;
|
|
||||||
|
|
||||||
spin_unlock(&xprt->transport_lock);
|
|
||||||
|
|
||||||
/* Race breaker in case memory is freed before above code is called */
|
|
||||||
if (ret == -EAGAIN) {
|
|
||||||
struct socket_wq *wq;
|
struct socket_wq *wq;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
@ -797,8 +787,42 @@ static int xs_nospace(struct rpc_rqst *req)
|
||||||
set_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags);
|
set_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
sk->sk_write_space(sk);
|
/* wait for more buffer space */
|
||||||
|
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||||
|
sk->sk_write_pending++;
|
||||||
|
xprt_wait_for_buffer_space(xprt);
|
||||||
|
} else
|
||||||
|
ret = -ENOTCONN;
|
||||||
|
|
||||||
|
spin_unlock(&xprt->transport_lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xs_sock_nospace(struct rpc_rqst *req)
|
||||||
|
{
|
||||||
|
struct sock_xprt *transport =
|
||||||
|
container_of(req->rq_xprt, struct sock_xprt, xprt);
|
||||||
|
struct sock *sk = transport->inet;
|
||||||
|
int ret = -EAGAIN;
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
if (!sock_writeable(sk))
|
||||||
|
ret = xs_nospace(req, transport);
|
||||||
|
release_sock(sk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xs_stream_nospace(struct rpc_rqst *req)
|
||||||
|
{
|
||||||
|
struct sock_xprt *transport =
|
||||||
|
container_of(req->rq_xprt, struct sock_xprt, xprt);
|
||||||
|
struct sock *sk = transport->inet;
|
||||||
|
int ret = -EAGAIN;
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
if (!sk_stream_memory_free(sk))
|
||||||
|
ret = xs_nospace(req, transport);
|
||||||
|
release_sock(sk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,7 +912,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
|
||||||
case -ENOBUFS:
|
case -ENOBUFS:
|
||||||
break;
|
break;
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
status = xs_nospace(req);
|
status = xs_stream_nospace(req);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dprintk("RPC: sendmsg returned unrecognized error %d\n",
|
dprintk("RPC: sendmsg returned unrecognized error %d\n",
|
||||||
|
@ -964,7 +988,7 @@ static int xs_udp_send_request(struct rpc_rqst *req)
|
||||||
/* Should we call xs_close() here? */
|
/* Should we call xs_close() here? */
|
||||||
break;
|
break;
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
status = xs_nospace(req);
|
status = xs_sock_nospace(req);
|
||||||
break;
|
break;
|
||||||
case -ENETUNREACH:
|
case -ENETUNREACH:
|
||||||
case -ENOBUFS:
|
case -ENOBUFS:
|
||||||
|
@ -1086,7 +1110,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
|
||||||
/* Should we call xs_close() here? */
|
/* Should we call xs_close() here? */
|
||||||
break;
|
break;
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
status = xs_nospace(req);
|
status = xs_stream_nospace(req);
|
||||||
break;
|
break;
|
||||||
case -ECONNRESET:
|
case -ECONNRESET:
|
||||||
case -ECONNREFUSED:
|
case -ECONNREFUSED:
|
||||||
|
|
Loading…
Reference in a new issue