From nobody Fri Dec 19 04:57:59 2025 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D588D18756A for ; Wed, 4 Dec 2024 07:48:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733298529; cv=none; b=MSP2dH7veQxUxuyS0nhuaKQ2xMdcugUfGjyjUOJKJ9OPC7KCETZzXqjQ4jBSutHlBPi7wrULSscqF1cdsG3TPPMj1SDENhYVh3PzATx6/LnY0YP6C4YVMj5NuapsCMUhMPf32l8Jo9m0I/qMRYJ9ep0SKAG0CYZmn9Zmispxeqo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733298529; c=relaxed/simple; bh=lIm1sfkgQdgswnNETY486ch/tTo3X6nN2DljFQj+Ohk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m1Wm/y4lwqoomA6zuxgs6i/iFwJ0BA2RvwEUQJdri0iYiXUqbzTwyTbbVEWvEBU/vBK/q5KyjC9w9Q5XkrvaLobZdjQNnFJ4cr04LfXzHrpmFbYP6MXZNH9tsKq0g+bUjDNxwL+cm2qsz41fWZouKxhNzOro6so+jN7dtcUkbI0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=jD6S2Bs7; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="jD6S2Bs7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733298526; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/7QeiBm2vEJMz1lK39zYjm8kRRwNv4rjIa8Oiam3+ww=; b=jD6S2Bs7UeqeFBfoc4Jk8egml3jGSbxo993tstKLf0/K77Qi5dHX+e1rBlwEvviVYJzte7 jxL57gkW1mHR6XHGwYvOdFb2yrloafcfE5GEoKfglHOEU3KcwjZ/FItUNnXpngJQp/lI/B Sroy0GqS9RY1JFiIKV8duyx8HecQ4qc= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-279-pfcyFQooMdiMR1FUr90ZyQ-1; Wed, 04 Dec 2024 02:48:42 -0500 X-MC-Unique: pfcyFQooMdiMR1FUr90ZyQ-1 X-Mimecast-MFC-AGG-ID: pfcyFQooMdiMR1FUr90ZyQ Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 75E6B1956088; Wed, 4 Dec 2024 07:48:41 +0000 (UTC) Received: from warthog.procyon.org.uk.com (unknown [10.42.28.48]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E9DAD19560A2; Wed, 4 Dec 2024 07:48:38 +0000 (UTC) From: David Howells To: netdev@vger.kernel.org Cc: David Howells , Marc Dionne , Yunsheng Lin , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-afs@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next v2 20/39] rxrpc: Replace call->acks_first_seq with tracking of the hard ACK point Date: Wed, 4 Dec 2024 07:46:48 +0000 Message-ID: <20241204074710.990092-21-dhowells@redhat.com> In-Reply-To: <20241204074710.990092-1-dhowells@redhat.com> References: <20241204074710.990092-1-dhowells@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Replace the call->acks_first_seq variable (which holds ack.firstPacket from the latest ACK packet and indicates the sequence number of the first ack slot in the SACK table) with call->acks_hard_ack which will hold the highest sequence hard ACK'd. This is 1 less than call->acks_first_seq, but it fits in the same schema as the other tracking variables which hold the sequence of a packet, not one past it. This will fix the rxrpc_congest tracepoint's calculation of SACK window size which shows one fewer than it should - and will occasionally go to -1. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- include/trace/events/rxrpc.h | 68 +++++++++++++++++------------------- net/rxrpc/ar-internal.h | 2 +- net/rxrpc/input.c | 56 ++++++++++++++--------------- 3 files changed, 59 insertions(+), 67 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 0f253287de00..91108e0de3af 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -893,7 +893,7 @@ TRACE_EVENT(rxrpc_txqueue, __field(unsigned int, call) __field(enum rxrpc_txqueue_trace, why) __field(rxrpc_seq_t, tx_bottom) - __field(rxrpc_seq_t, acks_first_seq) + __field(rxrpc_seq_t, acks_hard_ack) __field(rxrpc_seq_t, tx_top) __field(rxrpc_seq_t, send_top) __field(int, tx_winsize) @@ -903,19 +903,19 @@ TRACE_EVENT(rxrpc_txqueue, __entry->call =3D call->debug_id; __entry->why =3D why; __entry->tx_bottom =3D call->tx_bottom; - __entry->acks_first_seq =3D call->acks_first_seq; + __entry->acks_hard_ack =3D call->acks_hard_ack; __entry->tx_top =3D call->tx_top; __entry->send_top =3D call->send_top; __entry->tx_winsize =3D call->tx_winsize; ), =20 - TP_printk("c=3D%08x %s f=3D%08x h=3D%08x n=3D%u/%u/%u/%u", + TP_printk("c=3D%08x %s b=3D%08x h=3D%08x n=3D%u/%u/%u/%u", __entry->call, __print_symbolic(__entry->why, rxrpc_txqueue_traces), __entry->tx_bottom, - __entry->acks_first_seq, - __entry->acks_first_seq - __entry->tx_bottom, - __entry->tx_top - __entry->acks_first_seq, + __entry->acks_hard_ack, + __entry->acks_hard_ack - __entry->tx_bottom, + __entry->tx_top - __entry->acks_hard_ack, __entry->send_top - __entry->tx_top, __entry->tx_winsize) ); @@ -1015,11 +1015,9 @@ TRACE_EVENT(rxrpc_rx_data, ); =20 TRACE_EVENT(rxrpc_rx_ack, - TP_PROTO(struct rxrpc_call *call, - rxrpc_serial_t serial, rxrpc_serial_t ack_serial, - rxrpc_seq_t first, rxrpc_seq_t prev, u8 reason, u8 n_acks), + TP_PROTO(struct rxrpc_call *call, struct rxrpc_skb_priv *sp), =20 - TP_ARGS(call, serial, ack_serial, first, prev, reason, n_acks), + TP_ARGS(call, sp), =20 TP_STRUCT__entry( __field(unsigned int, call) @@ -1032,13 +1030,13 @@ TRACE_EVENT(rxrpc_rx_ack, ), =20 TP_fast_assign( - __entry->call =3D call->debug_id; - __entry->serial =3D serial; - __entry->ack_serial =3D ack_serial; - __entry->first =3D first; - __entry->prev =3D prev; - __entry->reason =3D reason; - __entry->n_acks =3D n_acks; + __entry->call =3D call->debug_id; + __entry->serial =3D sp->hdr.serial; + __entry->ack_serial =3D sp->ack.acked_serial; + __entry->first =3D sp->ack.first_ack; + __entry->prev =3D sp->ack.prev_ack; + __entry->reason =3D sp->ack.reason; + __entry->n_acks =3D sp->ack.nr_acks; ), =20 TP_printk("c=3D%08x %08x %s r=3D%08x f=3D%08x p=3D%08x n=3D%u", @@ -1707,7 +1705,7 @@ TRACE_EVENT(rxrpc_congest, TP_fast_assign( __entry->call =3D call->debug_id; __entry->change =3D change; - __entry->hard_ack =3D call->acks_first_seq; + __entry->hard_ack =3D call->acks_hard_ack; __entry->top =3D call->tx_top; __entry->lowest_nak =3D call->acks_lowest_nak; __entry->ack_serial =3D ack_serial; @@ -1754,7 +1752,7 @@ TRACE_EVENT(rxrpc_reset_cwnd, __entry->mode =3D call->cong_mode; __entry->cwnd =3D call->cong_cwnd; __entry->extra =3D call->cong_extra; - __entry->hard_ack =3D call->acks_first_seq; + __entry->hard_ack =3D call->acks_hard_ack; __entry->prepared =3D call->send_top - call->tx_bottom; __entry->since_last_tx =3D ktime_sub(now, call->tx_last_sent); __entry->has_data =3D call->tx_bottom !=3D call->tx_top; @@ -1855,7 +1853,7 @@ TRACE_EVENT(rxrpc_resend, TP_fast_assign( struct rxrpc_skb_priv *sp =3D ack ? rxrpc_skb(ack) : NULL; __entry->call =3D call->debug_id; - __entry->seq =3D call->acks_first_seq; + __entry->seq =3D call->acks_hard_ack; __entry->transmitted =3D call->tx_transmitted; __entry->ack_serial =3D sp ? sp->hdr.serial : 0; ), @@ -1944,7 +1942,7 @@ TRACE_EVENT(rxrpc_call_reset, __entry->call_id =3D call->call_id; __entry->call_serial =3D call->rx_serial; __entry->conn_serial =3D call->conn->hi_serial; - __entry->tx_seq =3D call->acks_first_seq; + __entry->tx_seq =3D call->acks_hard_ack; __entry->rx_seq =3D call->rx_highest_seq; ), =20 @@ -1976,38 +1974,36 @@ TRACE_EVENT(rxrpc_notify_socket, ); =20 TRACE_EVENT(rxrpc_rx_discard_ack, - TP_PROTO(unsigned int debug_id, rxrpc_serial_t serial, - rxrpc_seq_t first_soft_ack, rxrpc_seq_t call_ackr_first, - rxrpc_seq_t prev_pkt, rxrpc_seq_t call_ackr_prev), + TP_PROTO(struct rxrpc_call *call, rxrpc_serial_t serial, + rxrpc_seq_t hard_ack, rxrpc_seq_t prev_pkt), =20 - TP_ARGS(debug_id, serial, first_soft_ack, call_ackr_first, - prev_pkt, call_ackr_prev), + TP_ARGS(call, serial, hard_ack, prev_pkt), =20 TP_STRUCT__entry( __field(unsigned int, debug_id) __field(rxrpc_serial_t, serial) - __field(rxrpc_seq_t, first_soft_ack) - __field(rxrpc_seq_t, call_ackr_first) + __field(rxrpc_seq_t, hard_ack) __field(rxrpc_seq_t, prev_pkt) - __field(rxrpc_seq_t, call_ackr_prev) + __field(rxrpc_seq_t, acks_hard_ack) + __field(rxrpc_seq_t, acks_prev_seq) ), =20 TP_fast_assign( - __entry->debug_id =3D debug_id; + __entry->debug_id =3D call->debug_id; __entry->serial =3D serial; - __entry->first_soft_ack =3D first_soft_ack; - __entry->call_ackr_first =3D call_ackr_first; + __entry->hard_ack =3D hard_ack; __entry->prev_pkt =3D prev_pkt; - __entry->call_ackr_prev =3D call_ackr_prev; + __entry->acks_hard_ack =3D call->acks_hard_ack; + __entry->acks_prev_seq =3D call->acks_prev_seq; ), =20 TP_printk("c=3D%08x r=3D%08x %08x<%08x %08x<%08x", __entry->debug_id, __entry->serial, - __entry->first_soft_ack, - __entry->call_ackr_first, + __entry->hard_ack, + __entry->acks_hard_ack, __entry->prev_pkt, - __entry->call_ackr_prev) + __entry->acks_prev_seq) ); =20 TRACE_EVENT(rxrpc_req_ack, diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 6683043cee3f..3e57cef7385f 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -757,7 +757,7 @@ struct rxrpc_call { =20 /* Transmission-phase ACK management (ACKs we've received). */ ktime_t acks_latest_ts; /* Timestamp of latest ACK received */ - rxrpc_seq_t acks_first_seq; /* first sequence number received */ + rxrpc_seq_t acks_hard_ack; /* Highest sequence hard acked */ rxrpc_seq_t acks_prev_seq; /* Highest previousPacket received */ rxrpc_seq_t acks_lowest_nak; /* Lowest NACK in the buffer (or =3D=3Dtx_h= ard_ack) */ rxrpc_serial_t acks_highest_serial; /* Highest serial number ACK'd */ diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index afb87a3322da..b89fd0dee324 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -782,12 +782,12 @@ static void rxrpc_input_ack_trailer(struct rxrpc_call= *call, struct sk_buff *skb */ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rxrpc_call *call, struct rxrpc_ack_summary *summary, - rxrpc_seq_t seq) + rxrpc_seq_t hard_ack) { struct sk_buff *skb =3D call->cong_last_nack; struct rxrpc_skb_priv *sp =3D rxrpc_skb(skb); unsigned int i, new_acks =3D 0, retained_nacks =3D 0; - rxrpc_seq_t old_seq =3D sp->ack.first_ack; + rxrpc_seq_t seq =3D hard_ack + 1, old_seq =3D sp->ack.first_ack; u8 *acks =3D skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct= rxrpc_ackpacket); =20 if (after_eq(seq, old_seq + sp->ack.nr_acks)) { @@ -810,7 +810,7 @@ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rx= rpc_call *call, summary->nr_retained_nacks =3D retained_nacks; } =20 - return old_seq + sp->ack.nr_acks; + return old_seq + sp->ack.nr_acks - 1; } =20 /* @@ -825,22 +825,23 @@ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct = rxrpc_call *call, static void rxrpc_input_soft_acks(struct rxrpc_call *call, struct rxrpc_ack_summary *summary, struct sk_buff *skb, - rxrpc_seq_t seq, rxrpc_seq_t since) { struct rxrpc_skb_priv *sp =3D rxrpc_skb(skb); unsigned int i, old_nacks =3D 0; - rxrpc_seq_t lowest_nak =3D seq + sp->ack.nr_acks; + rxrpc_seq_t lowest_nak =3D call->acks_hard_ack + sp->ack.nr_acks + 1; + rxrpc_seq_t seq =3D call->acks_hard_ack; u8 *acks =3D skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct= rxrpc_ackpacket); =20 for (i =3D 0; i < sp->ack.nr_acks; i++) { + seq++; if (acks[i] =3D=3D RXRPC_ACK_TYPE_ACK) { summary->nr_acks++; - if (after_eq(seq, since)) + if (after(seq, since)) summary->nr_new_acks++; } else { summary->saw_nacks =3D true; - if (before(seq, since)) { + if (before_eq(seq, since)) { /* Overlap with previous ACK */ old_nacks++; } else { @@ -851,7 +852,6 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *ca= ll, if (before(seq, lowest_nak)) lowest_nak =3D seq; } - seq++; } =20 if (lowest_nak !=3D call->acks_lowest_nak) { @@ -874,21 +874,21 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *= call, * with respect to the ack state conveyed by preceding ACKs. */ static bool rxrpc_is_ack_valid(struct rxrpc_call *call, - rxrpc_seq_t first_pkt, rxrpc_seq_t prev_pkt) + rxrpc_seq_t hard_ack, rxrpc_seq_t prev_pkt) { - rxrpc_seq_t base =3D READ_ONCE(call->acks_first_seq); + rxrpc_seq_t base =3D READ_ONCE(call->acks_hard_ack); =20 - if (after(first_pkt, base)) + if (after(hard_ack, base)) return true; /* The window advanced */ =20 - if (before(first_pkt, base)) + if (before(hard_ack, base)) return false; /* firstPacket regressed */ =20 if (after_eq(prev_pkt, call->acks_prev_seq)) return true; /* previousPacket hasn't regressed. */ =20 /* Some rx implementations put a serial number in previousPacket. */ - if (after_eq(prev_pkt, base + call->tx_winsize)) + if (after(prev_pkt, base + call->tx_winsize)) return false; return true; } @@ -906,8 +906,8 @@ static bool rxrpc_is_ack_valid(struct rxrpc_call *call, static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) { struct rxrpc_ack_summary summary =3D { 0 }; - struct rxrpc_skb_priv *sp =3D rxrpc_skb(skb); struct rxrpc_acktrailer trailer; + struct rxrpc_skb_priv *sp =3D rxrpc_skb(skb); rxrpc_serial_t ack_serial, acked_serial; rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt, since; int nr_acks, offset, ioffset; @@ -925,9 +925,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, st= ruct sk_buff *skb) summary.ack_reason =3D (sp->ack.reason < RXRPC_ACK__INVALID ? sp->ack.reason : RXRPC_ACK__INVALID); =20 - trace_rxrpc_rx_ack(call, ack_serial, acked_serial, - first_soft_ack, prev_pkt, - summary.ack_reason, nr_acks); + trace_rxrpc_rx_ack(call, sp); rxrpc_inc_stat(call->rxnet, stat_rx_acks[summary.ack_reason]); =20 if (acked_serial !=3D 0) { @@ -952,7 +950,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, st= ruct sk_buff *skb) * lost the call because it switched to a different peer. */ if (unlikely(summary.ack_reason =3D=3D RXRPC_ACK_EXCEEDS_WINDOW) && - first_soft_ack =3D=3D 1 && + hard_ack =3D=3D 0 && prev_pkt =3D=3D 0 && rxrpc_is_client_call(call)) { rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED, @@ -965,7 +963,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, st= ruct sk_buff *skb) * if we still have it buffered to the beginning. */ if (unlikely(summary.ack_reason =3D=3D RXRPC_ACK_OUT_OF_SEQUENCE) && - first_soft_ack =3D=3D 1 && + hard_ack =3D=3D 0 && prev_pkt =3D=3D 0 && call->tx_bottom =3D=3D 0 && rxrpc_is_client_call(call)) { @@ -975,10 +973,8 @@ static void rxrpc_input_ack(struct rxrpc_call *call, s= truct sk_buff *skb) } =20 /* Discard any out-of-order or duplicate ACKs (outside lock). */ - if (!rxrpc_is_ack_valid(call, first_soft_ack, prev_pkt)) { - trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial, - first_soft_ack, call->acks_first_seq, - prev_pkt, call->acks_prev_seq); + if (!rxrpc_is_ack_valid(call, hard_ack, prev_pkt)) { + trace_rxrpc_rx_discard_ack(call, ack_serial, hard_ack, prev_pkt); goto send_response; } =20 @@ -992,17 +988,17 @@ static void rxrpc_input_ack(struct rxrpc_call *call, = struct sk_buff *skb) skb_condense(skb); =20 if (call->cong_last_nack) { - since =3D rxrpc_input_check_prev_ack(call, &summary, first_soft_ack); + since =3D rxrpc_input_check_prev_ack(call, &summary, hard_ack); rxrpc_free_skb(call->cong_last_nack, rxrpc_skb_put_last_nack); call->cong_last_nack =3D NULL; } else { - summary.nr_new_acks =3D first_soft_ack - call->acks_first_seq; - call->acks_lowest_nak =3D first_soft_ack + nr_acks; - since =3D first_soft_ack; + summary.nr_new_acks =3D hard_ack - call->acks_hard_ack; + call->acks_lowest_nak =3D hard_ack + nr_acks; + since =3D hard_ack; } =20 call->acks_latest_ts =3D skb->tstamp; - call->acks_first_seq =3D first_soft_ack; + call->acks_hard_ack =3D hard_ack; call->acks_prev_seq =3D prev_pkt; =20 switch (summary.ack_reason) { @@ -1018,7 +1014,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, = struct sk_buff *skb) if (trailer.maxMTU) rxrpc_input_ack_trailer(call, skb, &trailer); =20 - if (first_soft_ack =3D=3D 0) + if (hard_ack + 1 =3D=3D 0) return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero); =20 /* Ignore ACKs unless we are or have just been transmitting. */ @@ -1048,7 +1044,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, = struct sk_buff *skb) if (nr_acks > 0) { if (offset > (int)skb->len - nr_acks) return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_short_sack); - rxrpc_input_soft_acks(call, &summary, skb, first_soft_ack, since); + rxrpc_input_soft_acks(call, &summary, skb, since); rxrpc_get_skb(skb, rxrpc_skb_get_last_nack); call->cong_last_nack =3D skb; }