rxrpc: Send an ACK after every few DATA packets we receive
authorDavid Howells <dhowells@redhat.com>
Sat, 24 Sep 2016 17:05:26 +0000 (18:05 +0100)
committerDavid Howells <dhowells@redhat.com>
Sat, 24 Sep 2016 17:05:26 +0000 (18:05 +0100)
Send an ACK if we haven't sent one for the last two packets we've received.
This keeps the other end apprised of where we've got to - which is
important if they're doing slow-start.

We do this in recvmsg so that we can dispatch a packet directly without the
need to wake up the background thread.

This should possibly be made configurable in future.

Signed-off-by: David Howells <dhowells@redhat.com>
net/rxrpc/ar-internal.h
net/rxrpc/misc.c
net/rxrpc/output.c
net/rxrpc/recvmsg.c

index 042dbcc5265487026389f1815c02bbc83fdc95bf..e3bf9c0e3ad113e19a535c2acad2a797516e9373 100644 (file)
@@ -533,6 +533,8 @@ struct rxrpc_call {
        u16                     ackr_skew;      /* skew on packet being ACK'd */
        rxrpc_serial_t          ackr_serial;    /* serial of packet being ACK'd */
        rxrpc_seq_t             ackr_prev_seq;  /* previous sequence number received */
+       rxrpc_seq_t             ackr_consumed;  /* Highest packet shown consumed */
+       rxrpc_seq_t             ackr_seen;      /* Highest packet shown seen */
        rxrpc_serial_t          ackr_ping;      /* Last ping sent */
        ktime_t                 ackr_ping_time; /* Time last ping sent */
 
@@ -695,6 +697,7 @@ enum rxrpc_propose_ack_trace {
        rxrpc_propose_ack_respond_to_ack,
        rxrpc_propose_ack_respond_to_ping,
        rxrpc_propose_ack_retry_tx,
+       rxrpc_propose_ack_rotate_rx,
        rxrpc_propose_ack_terminal_ack,
        rxrpc_propose_ack__nr_trace
 };
index 1ca14835d87f9652b98d9b20ad3aa5172babfb55..a473fd7dabaa0f9564766a785c56d49a87f091c3 100644 (file)
@@ -202,6 +202,7 @@ const char rxrpc_propose_ack_traces[rxrpc_propose_ack__nr_trace][8] = {
        [rxrpc_propose_ack_respond_to_ack]      = "Rsp2Ack",
        [rxrpc_propose_ack_respond_to_ping]     = "Rsp2Png",
        [rxrpc_propose_ack_retry_tx]            = "RetryTx",
+       [rxrpc_propose_ack_rotate_rx]           = "RxAck  ",
        [rxrpc_propose_ack_terminal_ack]        = "ClTerm ",
 };
 
index 0c563e325c9d8e72ffad9abb24e8007ca2aef8f9..3eb01445e8146daf6c0f18941fbe746713214e05 100644 (file)
@@ -36,7 +36,9 @@ struct rxrpc_pkt_buffer {
  * Fill out an ACK packet.
  */
 static size_t rxrpc_fill_out_ack(struct rxrpc_call *call,
-                                struct rxrpc_pkt_buffer *pkt)
+                                struct rxrpc_pkt_buffer *pkt,
+                                rxrpc_seq_t *_hard_ack,
+                                rxrpc_seq_t *_top)
 {
        rxrpc_serial_t serial;
        rxrpc_seq_t hard_ack, top, seq;
@@ -48,6 +50,8 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_call *call,
        serial = call->ackr_serial;
        hard_ack = READ_ONCE(call->rx_hard_ack);
        top = smp_load_acquire(&call->rx_top);
+       *_hard_ack = hard_ack;
+       *_top = top;
 
        pkt->ack.bufferSpace    = htons(8);
        pkt->ack.maxSkew        = htons(call->ackr_skew);
@@ -96,6 +100,7 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
        struct msghdr msg;
        struct kvec iov[2];
        rxrpc_serial_t serial;
+       rxrpc_seq_t hard_ack, top;
        size_t len, n;
        bool ping = false;
        int ioc, ret;
@@ -146,7 +151,7 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
                        goto out;
                }
                ping = (call->ackr_reason == RXRPC_ACK_PING);
-               n = rxrpc_fill_out_ack(call, pkt);
+               n = rxrpc_fill_out_ack(call, pkt, &hard_ack, &top);
                call->ackr_reason = 0;
 
                spin_unlock_bh(&call->lock);
@@ -203,18 +208,22 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
        if (ping)
                call->ackr_ping_time = ktime_get_real();
 
-       if (ret < 0 && call->state < RXRPC_CALL_COMPLETE) {
-               switch (type) {
-               case RXRPC_PACKET_TYPE_ACK:
+       if (type == RXRPC_PACKET_TYPE_ACK &&
+           call->state < RXRPC_CALL_COMPLETE) {
+               if (ret < 0) {
                        clear_bit(RXRPC_CALL_PINGING, &call->flags);
                        rxrpc_propose_ACK(call, pkt->ack.reason,
                                          ntohs(pkt->ack.maxSkew),
                                          ntohl(pkt->ack.serial),
                                          true, true,
                                          rxrpc_propose_ack_retry_tx);
-                       break;
-               case RXRPC_PACKET_TYPE_ABORT:
-                       break;
+               } else {
+                       spin_lock_bh(&call->lock);
+                       if (after(hard_ack, call->ackr_consumed))
+                               call->ackr_consumed = hard_ack;
+                       if (after(top, call->ackr_seen))
+                               call->ackr_seen = top;
+                       spin_unlock_bh(&call->lock);
                }
        }
 
index 8c7f3de45bac1c17e542ac4afe299d167e42b6bd..a7458c398b9e5a6ee491bf4472a9a3ea683a1544 100644 (file)
@@ -201,8 +201,19 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
 
        _debug("%u,%u,%02x", hard_ack, top, flags);
        trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack);
-       if (flags & RXRPC_LAST_PACKET)
+       if (flags & RXRPC_LAST_PACKET) {
                rxrpc_end_rx_phase(call);
+       } else {
+               /* Check to see if there's an ACK that needs sending. */
+               if (after_eq(hard_ack, call->ackr_consumed + 2) ||
+                   after_eq(top, call->ackr_seen + 2) ||
+                   (hard_ack == top && after(hard_ack, call->ackr_consumed)))
+                       rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, 0, serial,
+                                         true, false,
+                                         rxrpc_propose_ack_rotate_rx);
+               if (call->ackr_reason)
+                       rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ACK);
+       }
 }
 
 /*