aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-01-06 08:57:06 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2016-01-06 12:22:25 -0500
commit13331a551ab4df87f7a027d2cab392da96aba1de (patch)
treef6af42644253993712cd87b467355b570bc6646b /net
parent0b161e6330e27c191a0ff0d44082ff7832a8c8a1 (diff)
SUNRPC: Fixup socket wait for memory
We're seeing hangs in the NFS client code, with loops of the form: RPC: 30317 xmit incomplete (267368 left of 524448) RPC: 30317 call_status (status -11) RPC: 30317 call_transmit (status 0) RPC: 30317 xprt_prepare_transmit RPC: 30317 xprt_transmit(524448) RPC: xs_tcp_send_request(267368) = -11 RPC: 30317 xmit incomplete (267368 left of 524448) RPC: 30317 call_status (status -11) RPC: 30317 call_transmit (status 0) RPC: 30317 xprt_prepare_transmit RPC: 30317 xprt_transmit(524448) Turns out commit ceb5d58b2170 ("net: fix sock_wake_async() rcu protection") moved SOCKWQ_ASYNC_NOSPACE out of sock->flags and into sk->sk_wq->flags, however it never tried to fix up the code in net/sunrpc. The new idiom is to use the flags in the RCU protected struct socket_wq. While we're at it, clear out the now redundant places where we set/clear SOCKWQ_ASYNC_NOSPACE and SOCK_NOSPACE. In principle, sk_stream_wait_memory() is supposed to set these for us, so we only need to clear them in the particular case of our ->write_space() callback. Fixes: ceb5d58b2170 ("net: fix sock_wake_async() rcu protection") Cc: Eric Dumazet <edumazet@google.com> Cc: stable@vger.kernel.org # 4.4 Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/xprtsock.c49
1 files changed, 21 insertions, 28 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 2ffaf6a79499..027c9ef8a263 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -398,7 +398,6 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
398 if (unlikely(!sock)) 398 if (unlikely(!sock))
399 return -ENOTSOCK; 399 return -ENOTSOCK;
400 400
401 clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags);
402 if (base != 0) { 401 if (base != 0) {
403 addr = NULL; 402 addr = NULL;
404 addrlen = 0; 403 addrlen = 0;
@@ -442,7 +441,6 @@ static void xs_nospace_callback(struct rpc_task *task)
442 struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); 441 struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
443 442
444 transport->inet->sk_write_pending--; 443 transport->inet->sk_write_pending--;
445 clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
446} 444}
447 445
448/** 446/**
@@ -467,20 +465,11 @@ static int xs_nospace(struct rpc_task *task)
467 465
468 /* Don't race with disconnect */ 466 /* Don't race with disconnect */
469 if (xprt_connected(xprt)) { 467 if (xprt_connected(xprt)) {
470 if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) { 468 /* wait for more buffer space */
471 /* 469 sk->sk_write_pending++;
472 * Notify TCP that we're limited by the application 470 xprt_wait_for_buffer_space(task, xs_nospace_callback);
473 * window size 471 } else
474 */
475 set_bit(SOCK_NOSPACE, &transport->sock->flags);
476 sk->sk_write_pending++;
477 /* ...and wait for more buffer space */
478 xprt_wait_for_buffer_space(task, xs_nospace_callback);
479 }
480 } else {
481 clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
482 ret = -ENOTCONN; 472 ret = -ENOTCONN;
483 }
484 473
485 spin_unlock_bh(&xprt->transport_lock); 474 spin_unlock_bh(&xprt->transport_lock);
486 475
@@ -616,9 +605,6 @@ process_status:
616 case -EAGAIN: 605 case -EAGAIN:
617 status = xs_nospace(task); 606 status = xs_nospace(task);
618 break; 607 break;
619 default:
620 dprintk("RPC: sendmsg returned unrecognized error %d\n",
621 -status);
622 case -ENETUNREACH: 608 case -ENETUNREACH:
623 case -ENOBUFS: 609 case -ENOBUFS:
624 case -EPIPE: 610 case -EPIPE:
@@ -626,7 +612,10 @@ process_status:
626 case -EPERM: 612 case -EPERM:
627 /* When the server has died, an ICMP port unreachable message 613 /* When the server has died, an ICMP port unreachable message
628 * prompts ECONNREFUSED. */ 614 * prompts ECONNREFUSED. */
629 clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); 615 break;
616 default:
617 dprintk("RPC: sendmsg returned unrecognized error %d\n",
618 -status);
630 } 619 }
631 620
632 return status; 621 return status;
@@ -706,16 +695,16 @@ static int xs_tcp_send_request(struct rpc_task *task)
706 case -EAGAIN: 695 case -EAGAIN:
707 status = xs_nospace(task); 696 status = xs_nospace(task);
708 break; 697 break;
709 default:
710 dprintk("RPC: sendmsg returned unrecognized error %d\n",
711 -status);
712 case -ECONNRESET: 698 case -ECONNRESET:
713 case -ECONNREFUSED: 699 case -ECONNREFUSED:
714 case -ENOTCONN: 700 case -ENOTCONN:
715 case -EADDRINUSE: 701 case -EADDRINUSE:
716 case -ENOBUFS: 702 case -ENOBUFS:
717 case -EPIPE: 703 case -EPIPE:
718 clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); 704 break;
705 default:
706 dprintk("RPC: sendmsg returned unrecognized error %d\n",
707 -status);
719 } 708 }
720 709
721 return status; 710 return status;
@@ -1609,19 +1598,23 @@ static void xs_tcp_state_change(struct sock *sk)
1609 1598
1610static void xs_write_space(struct sock *sk) 1599static void xs_write_space(struct sock *sk)
1611{ 1600{
1612 struct socket *sock; 1601 struct socket_wq *wq;
1613 struct rpc_xprt *xprt; 1602 struct rpc_xprt *xprt;
1614 1603
1615 if (unlikely(!(sock = sk->sk_socket))) 1604 if (!sk->sk_socket)
1616 return; 1605 return;
1617 clear_bit(SOCK_NOSPACE, &sock->flags); 1606 clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
1618 1607
1619 if (unlikely(!(xprt = xprt_from_sock(sk)))) 1608 if (unlikely(!(xprt = xprt_from_sock(sk))))
1620 return; 1609 return;
1621 if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0) 1610 rcu_read_lock();
1622 return; 1611 wq = rcu_dereference(sk->sk_wq);
1612 if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
1613 goto out;
1623 1614
1624 xprt_write_space(xprt); 1615 xprt_write_space(xprt);
1616out:
1617 rcu_read_unlock();
1625} 1618}
1626 1619
1627/** 1620/**