diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-05-29 00:42:03 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-06-13 12:35:51 -0400 |
commit | 9ffadfbc092fc25d9639a019fb3079cf352ef978 (patch) | |
tree | b2aa602f609bc2ef9aa11029269927dab517b5e1 /net | |
parent | f1dc237c60a5fdecc83062a28a702193f881cb19 (diff) | |
download | linux-stable-9ffadfbc092fc25d9639a019fb3079cf352ef978.tar.gz linux-stable-9ffadfbc092fc25d9639a019fb3079cf352ef978.tar.bz2 linux-stable-9ffadfbc092fc25d9639a019fb3079cf352ef978.zip |
SUNRPC: Fix suspicious enobufs issues.
The current test is racy when dealing with fast NICs.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/xprtsock.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 646170d0cb86..6b3efeb3edc5 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -642,6 +642,7 @@ static int xs_tcp_send_request(struct rpc_task *task) struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; bool zerocopy = true; + bool vm_wait = false; int status; int sent; @@ -677,15 +678,33 @@ static int xs_tcp_send_request(struct rpc_task *task) return 0; } + WARN_ON_ONCE(sent == 0 && status == 0); + + if (status == -EAGAIN ) { + /* + * Return EAGAIN if we're sure we're hitting the + * socket send buffer limits. + */ + if (test_bit(SOCK_NOSPACE, &transport->sock->flags)) + break; + /* + * Did we hit a memory allocation failure? + */ + if (sent == 0) { + status = -ENOBUFS; + if (vm_wait) + break; + /* Retry, knowing now that we're below the + * socket send buffer limit + */ + vm_wait = true; + } + continue; + } if (status < 0) break; - if (sent == 0) { - status = -EAGAIN; - break; - } + vm_wait = false; } - if (status == -EAGAIN && sk_stream_is_writeable(transport->inet)) - status = -ENOBUFS; switch (status) { case -ENOTSOCK: |