Commit 702f2ac8 authored by David Howells's avatar David Howells Committed by David S. Miller

rxrpc: Wake up the transmitter if Rx window size increases on the peer

The RxRPC ACK packet may contain an extension that includes the peer's
current Rx window size for this call.  We adjust the local Tx window size
to match.  However, the transmitter can stall if the receive window is
reduced to 0 by the peer and then reopened.

This is because the normal way that the transmitter is re-energised is by
dropping something out of our Tx queue and thus making space.  When a
single gap is made, the transmitter is woken up.  However, because there's
nothing in the Tx queue at this point, this doesn't happen.

To fix this, perform a wake_up() any time we see the peer's Rx window size
increasing.

The observable symptom is that calls start failing on ETIMEDOUT and the
following:

	kAFS: SERVER DEAD state=-62

appears in dmesg.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 29673983
...@@ -652,6 +652,7 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -652,6 +652,7 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_peer *peer; struct rxrpc_peer *peer;
unsigned int mtu; unsigned int mtu;
bool wake = false;
u32 rwind = ntohl(ackinfo->rwind); u32 rwind = ntohl(ackinfo->rwind);
_proto("Rx ACK %%%u Info { rx=%u max=%u rwin=%u jm=%u }", _proto("Rx ACK %%%u Info { rx=%u max=%u rwin=%u jm=%u }",
...@@ -659,9 +660,14 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -659,9 +660,14 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
ntohl(ackinfo->rxMTU), ntohl(ackinfo->maxMTU), ntohl(ackinfo->rxMTU), ntohl(ackinfo->maxMTU),
rwind, ntohl(ackinfo->jumbo_max)); rwind, ntohl(ackinfo->jumbo_max));
if (rwind > RXRPC_RXTX_BUFF_SIZE - 1) if (call->tx_winsize != rwind) {
rwind = RXRPC_RXTX_BUFF_SIZE - 1; if (rwind > RXRPC_RXTX_BUFF_SIZE - 1)
call->tx_winsize = rwind; rwind = RXRPC_RXTX_BUFF_SIZE - 1;
if (rwind > call->tx_winsize)
wake = true;
call->tx_winsize = rwind;
}
if (call->cong_ssthresh > rwind) if (call->cong_ssthresh > rwind)
call->cong_ssthresh = rwind; call->cong_ssthresh = rwind;
...@@ -675,6 +681,9 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -675,6 +681,9 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
spin_unlock_bh(&peer->lock); spin_unlock_bh(&peer->lock);
_net("Net MTU %u (maxdata %u)", peer->mtu, peer->maxdata); _net("Net MTU %u (maxdata %u)", peer->mtu, peer->maxdata);
} }
if (wake)
wake_up(&call->waitq);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment