rxrpc: Pass the last Tx packet marker in the annotation buffer
When the last packet of data to be transmitted on a call is queued, tx_top is set and then the RXRPC_CALL_TX_LAST flag is set. Unfortunately, this leaves a race in the ACK processing side of things because the flag affects the interpretation of tx_top and also allows us to start receiving reply data before we've finished transmitting. To fix this, make the following changes: (1) rxrpc_queue_packet() now sets a marker in the annotation buffer instead of setting the RXRPC_CALL_TX_LAST flag. (2) rxrpc_rotate_tx_window() detects the marker and sets the flag in the same context as the routines that use it. (3) rxrpc_end_tx_phase() is simplified to just shift the call state. The Tx window must have been rotated before calling to discard the last packet. (4) rxrpc_receiving_reply() is added to handle the arrival of the first DATA packet of a reply to a client call (which is an implicit ACK of the Tx phase). (5) The last part of rxrpc_input_ack() is reordered to perform Tx rotation, then soft-ACK application and then to end the phase if we've rotated the last packet. In the event of a terminal ACK, the soft-ACK application will be skipped as nAcks should be 0. (6) rxrpc_input_ackall() now has to rotate as well as ending the phase. In addition: (7) Alter the transmit tracepoint to log the rotation of the last packet. (8) Remove the no-longer relevant queue_reqack tracepoint note. The ACK-REQUESTED packet header flag is now set as needed when we actually transmit the packet and may vary by retransmission. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -94,11 +94,15 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
rxrpc_seq_t seq = sp->hdr.seq;
|
||||
int ret, ix;
|
||||
u8 annotation = RXRPC_TX_ANNO_UNACK;
|
||||
|
||||
_net("queue skb %p [%d]", skb, seq);
|
||||
|
||||
ASSERTCMP(seq, ==, call->tx_top + 1);
|
||||
|
||||
if (last)
|
||||
annotation |= RXRPC_TX_ANNO_LAST;
|
||||
|
||||
/* We have to set the timestamp before queueing as the retransmit
|
||||
* algorithm can see the packet as soon as we queue it.
|
||||
*/
|
||||
@@ -106,18 +110,14 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
|
||||
ix = seq & RXRPC_RXTX_BUFF_MASK;
|
||||
rxrpc_get_skb(skb, rxrpc_skb_tx_got);
|
||||
call->rxtx_annotations[ix] = RXRPC_TX_ANNO_UNACK;
|
||||
call->rxtx_annotations[ix] = annotation;
|
||||
smp_wmb();
|
||||
call->rxtx_buffer[ix] = skb;
|
||||
call->tx_top = seq;
|
||||
if (last) {
|
||||
set_bit(RXRPC_CALL_TX_LAST, &call->flags);
|
||||
if (last)
|
||||
trace_rxrpc_transmit(call, rxrpc_transmit_queue_last);
|
||||
} else if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
|
||||
trace_rxrpc_transmit(call, rxrpc_transmit_queue_reqack);
|
||||
} else {
|
||||
else
|
||||
trace_rxrpc_transmit(call, rxrpc_transmit_queue);
|
||||
}
|
||||
|
||||
if (last || call->state == RXRPC_CALL_SERVER_ACK_REQUEST) {
|
||||
_debug("________awaiting reply/ACK__________");
|
||||
|
Reference in New Issue
Block a user