| From foo@baz Sun Jun 17 12:07:34 CEST 2018 |
| From: David Howells <dhowells@redhat.com> |
| Date: Thu, 10 May 2018 23:26:00 +0100 |
| Subject: rxrpc: Fix missing start of call timeout |
| |
| From: David Howells <dhowells@redhat.com> |
| |
| [ Upstream commit c54e43d752c7187595c8c62a231e0b0d53c7fded ] |
| |
| The expect_rx_by call timeout is supposed to be set when a call is started |
| to indicate that we need to receive a packet by that point. This is |
| currently put back every time we receive a packet, but it isn't started |
| when we first send a packet. Without this, the call may wait forever if |
| the server doesn't deign to reply. |
| |
| Fix this by setting the timeout upon a successful UDP sendmsg call for the |
| first DATA packet. The timeout is initiated only for initial transmission |
| and not for subsequent retries as we don't want the retry mechanism to |
| extend the timeout indefinitely. |
| |
| Fixes: a158bdd3247b ("rxrpc: Fix call timeouts") |
| Reported-by: Marc Dionne <marc.dionne@auristor.com> |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/rxrpc/ar-internal.h | 1 + |
| net/rxrpc/input.c | 2 +- |
| net/rxrpc/output.c | 11 +++++++++++ |
| net/rxrpc/sendmsg.c | 10 ++++++++++ |
| 4 files changed, 23 insertions(+), 1 deletion(-) |
| |
| --- a/net/rxrpc/ar-internal.h |
| +++ b/net/rxrpc/ar-internal.h |
| @@ -464,6 +464,7 @@ enum rxrpc_call_flag { |
| RXRPC_CALL_SEND_PING, /* A ping will need to be sent */ |
| RXRPC_CALL_PINGING, /* Ping in process */ |
| RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */ |
| + RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */ |
| }; |
| |
| /* |
| --- a/net/rxrpc/input.c |
| +++ b/net/rxrpc/input.c |
| @@ -971,7 +971,7 @@ static void rxrpc_input_call_packet(stru |
| if (timo) { |
| unsigned long now = jiffies, expect_rx_by; |
| |
| - expect_rx_by = jiffies + timo; |
| + expect_rx_by = now + timo; |
| WRITE_ONCE(call->expect_rx_by, expect_rx_by); |
| rxrpc_reduce_call_timer(call, expect_rx_by, now, |
| rxrpc_timer_set_for_normal); |
| --- a/net/rxrpc/output.c |
| +++ b/net/rxrpc/output.c |
| @@ -407,6 +407,17 @@ done: |
| rxrpc_timer_set_for_lost_ack); |
| } |
| } |
| + |
| + if (sp->hdr.seq == 1 && |
| + !test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, |
| + &call->flags)) { |
| + unsigned long nowj = jiffies, expect_rx_by; |
| + |
| + expect_rx_by = nowj + call->next_rx_timo; |
| + WRITE_ONCE(call->expect_rx_by, expect_rx_by); |
| + rxrpc_reduce_call_timer(call, expect_rx_by, nowj, |
| + rxrpc_timer_set_for_normal); |
| + } |
| } |
| |
| rxrpc_set_keepalive(call); |
| --- a/net/rxrpc/sendmsg.c |
| +++ b/net/rxrpc/sendmsg.c |
| @@ -223,6 +223,15 @@ static void rxrpc_queue_packet(struct rx |
| |
| ret = rxrpc_send_data_packet(call, skb, false); |
| if (ret < 0) { |
| + switch (ret) { |
| + case -ENETUNREACH: |
| + case -EHOSTUNREACH: |
| + case -ECONNREFUSED: |
| + rxrpc_set_call_completion(call, |
| + RXRPC_CALL_LOCAL_ERROR, |
| + 0, ret); |
| + goto out; |
| + } |
| _debug("need instant resend %d", ret); |
| rxrpc_instant_resend(call, ix); |
| } else { |
| @@ -241,6 +250,7 @@ static void rxrpc_queue_packet(struct rx |
| rxrpc_timer_set_for_send); |
| } |
| |
| +out: |
| rxrpc_free_skb(skb, rxrpc_skb_tx_freed); |
| _leave(""); |
| } |