Commit 9a3dedcf authored by David Howells's avatar David Howells Committed by David S. Miller

rxrpc: Fix decision on when to generate an IDLE ACK

Fix the decision on when to generate an IDLE ACK by keeping a count of the
number of packets we've received, but not yet soft-ACK'd, and the number of
packets we've processed, but not yet hard-ACK'd, rather than trying to keep
track of which DATA sequence numbers correspond to those points.

We then generate an ACK when either counter exceeds 2.  The counters are
both cleared when we transcribe the information into any sort of ACK packet
for transmission.  IDLE and DELAY ACKs are skipped if both counters are 0
(ie. no change).

Fixes: 805b21b9 ("rxrpc: Send an ACK after every few DATA packets we receive")
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 81524b63
...@@ -1509,7 +1509,7 @@ TRACE_EVENT(rxrpc_call_reset, ...@@ -1509,7 +1509,7 @@ TRACE_EVENT(rxrpc_call_reset,
__entry->call_serial = call->rx_serial; __entry->call_serial = call->rx_serial;
__entry->conn_serial = call->conn->hi_serial; __entry->conn_serial = call->conn->hi_serial;
__entry->tx_seq = call->tx_hard_ack; __entry->tx_seq = call->tx_hard_ack;
__entry->rx_seq = call->ackr_seen; __entry->rx_seq = call->rx_hard_ack;
), ),
TP_printk("c=%08x %08x:%08x r=%08x/%08x tx=%08x rx=%08x", TP_printk("c=%08x %08x:%08x r=%08x/%08x tx=%08x rx=%08x",
......
...@@ -680,8 +680,8 @@ struct rxrpc_call { ...@@ -680,8 +680,8 @@ struct rxrpc_call {
u8 ackr_reason; /* reason to ACK */ u8 ackr_reason; /* reason to ACK */
rxrpc_serial_t ackr_serial; /* serial of packet being ACK'd */ rxrpc_serial_t ackr_serial; /* serial of packet being ACK'd */
rxrpc_seq_t ackr_highest_seq; /* Higest sequence number received */ rxrpc_seq_t ackr_highest_seq; /* Higest sequence number received */
rxrpc_seq_t ackr_consumed; /* Highest packet shown consumed */ atomic_t ackr_nr_unacked; /* Number of unacked packets */
rxrpc_seq_t ackr_seen; /* Highest packet shown seen */ atomic_t ackr_nr_consumed; /* Number of packets needing hard ACK */
/* RTT management */ /* RTT management */
rxrpc_serial_t rtt_serial[4]; /* Serial number of DATA or PING sent */ rxrpc_serial_t rtt_serial[4]; /* Serial number of DATA or PING sent */
......
...@@ -412,8 +412,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -412,8 +412,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
enum rxrpc_call_state state; enum rxrpc_call_state state;
unsigned int j, nr_subpackets; unsigned int j, nr_subpackets, nr_unacked = 0;
rxrpc_serial_t serial = sp->hdr.serial, ack_serial = 0; rxrpc_serial_t serial = sp->hdr.serial, ack_serial = serial;
rxrpc_seq_t seq0 = sp->hdr.seq, hard_ack; rxrpc_seq_t seq0 = sp->hdr.seq, hard_ack;
bool immediate_ack = false, jumbo_bad = false; bool immediate_ack = false, jumbo_bad = false;
u8 ack = 0; u8 ack = 0;
...@@ -569,6 +569,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -569,6 +569,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
sp = NULL; sp = NULL;
} }
nr_unacked++;
if (last) { if (last) {
set_bit(RXRPC_CALL_RX_LAST, &call->flags); set_bit(RXRPC_CALL_RX_LAST, &call->flags);
if (!ack) { if (!ack) {
...@@ -588,9 +590,14 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -588,9 +590,14 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
} }
call->rx_expect_next = seq + 1; call->rx_expect_next = seq + 1;
} }
if (!ack)
ack_serial = serial;
} }
ack: ack:
if (atomic_add_return(nr_unacked, &call->ackr_nr_unacked) > 2 && !ack)
ack = RXRPC_ACK_IDLE;
if (ack) if (ack)
rxrpc_propose_ACK(call, ack, ack_serial, rxrpc_propose_ACK(call, ack, ack_serial,
immediate_ack, true, immediate_ack, true,
......
...@@ -74,11 +74,18 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, ...@@ -74,11 +74,18 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
u8 reason) u8 reason)
{ {
rxrpc_serial_t serial; rxrpc_serial_t serial;
unsigned int tmp;
rxrpc_seq_t hard_ack, top, seq; rxrpc_seq_t hard_ack, top, seq;
int ix; int ix;
u32 mtu, jmax; u32 mtu, jmax;
u8 *ackp = pkt->acks; u8 *ackp = pkt->acks;
tmp = atomic_xchg(&call->ackr_nr_unacked, 0);
tmp |= atomic_xchg(&call->ackr_nr_consumed, 0);
if (!tmp && (reason == RXRPC_ACK_DELAY ||
reason == RXRPC_ACK_IDLE))
return 0;
/* Barrier against rxrpc_input_data(). */ /* Barrier against rxrpc_input_data(). */
serial = call->ackr_serial; serial = call->ackr_serial;
hard_ack = READ_ONCE(call->rx_hard_ack); hard_ack = READ_ONCE(call->rx_hard_ack);
...@@ -223,6 +230,10 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping, ...@@ -223,6 +230,10 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
n = rxrpc_fill_out_ack(conn, call, pkt, &hard_ack, &top, reason); n = rxrpc_fill_out_ack(conn, call, pkt, &hard_ack, &top, reason);
spin_unlock_bh(&call->lock); spin_unlock_bh(&call->lock);
if (n == 0) {
kfree(pkt);
return 0;
}
iov[0].iov_base = pkt; iov[0].iov_base = pkt;
iov[0].iov_len = sizeof(pkt->whdr) + sizeof(pkt->ack) + n; iov[0].iov_len = sizeof(pkt->whdr) + sizeof(pkt->ack) + n;
...@@ -259,13 +270,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping, ...@@ -259,13 +270,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
ntohl(pkt->ack.serial), ntohl(pkt->ack.serial),
false, true, false, true,
rxrpc_propose_ack_retry_tx); rxrpc_propose_ack_retry_tx);
} 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);
} }
rxrpc_set_keepalive(call); rxrpc_set_keepalive(call);
......
...@@ -260,11 +260,9 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) ...@@ -260,11 +260,9 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
rxrpc_end_rx_phase(call, serial); rxrpc_end_rx_phase(call, serial);
} else { } else {
/* Check to see if there's an ACK that needs sending. */ /* Check to see if there's an ACK that needs sending. */
if (after_eq(hard_ack, call->ackr_consumed + 2) || if (atomic_inc_return(&call->ackr_nr_consumed) > 2)
after_eq(top, call->ackr_seen + 2) || rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial,
(hard_ack == top && after(hard_ack, call->ackr_consumed))) true, false,
rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial,
true, true,
rxrpc_propose_ack_rotate_rx); rxrpc_propose_ack_rotate_rx);
if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY) if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY)
rxrpc_send_ack_packet(call, false, NULL); rxrpc_send_ack_packet(call, false, NULL);
......
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