rxrpc: Fix missing start of call timeout
authorDavid Howells <dhowells@redhat.com>
Thu, 10 May 2018 22:26:00 +0000 (23:26 +0100)
committerDavid Howells <dhowells@redhat.com>
Thu, 10 May 2018 22:26:00 +0000 (23:26 +0100)
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>
net/rxrpc/ar-internal.h
net/rxrpc/input.c
net/rxrpc/output.c
net/rxrpc/sendmsg.c

index 90d7079e0aa99327ced07c61d4c8e315fbe26f8d..19975d2ca9a20367d900f14ab8b776953e3d5ba1 100644 (file)
@@ -476,6 +476,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 */
 };
 
 /*
index 0410d2277ca28bcf0259df897581b947f707fac1..b5fd6381313d06b1b02ad6e6f6ca5c0dcc74b10d 100644 (file)
@@ -971,7 +971,7 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,
        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);
index 7f1fc04775b34e5abd8e24a450ae386e74bf194a..6b9d27f0d7ecd288b0ed4bd16fd4b15987b386b4 100644 (file)
@@ -414,6 +414,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);
index 206e802ccbdc1a588ad26e13ff5f7e66afa6c4bb..be01f9c5d963ddfc766fac811ace9a381b89a7f7 100644 (file)
@@ -223,6 +223,15 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
 
        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 rxrpc_sock *rx, struct rxrpc_call *call,
                                        rxrpc_timer_set_for_send);
        }
 
+out:
        rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
        _leave("");
 }