git: e34ea0196f44 - main - tcp: clear all TCP timers in tcp_timer_stop() when in callout
Date: Mon, 18 Mar 2024 20:57:10 UTC
The branch main has been updated by glebius:
URL: https://cgit.FreeBSD.org/src/commit/?id=e34ea0196f4497d3f3939025aff3a89ee77b652e
commit e34ea0196f4497d3f3939025aff3a89ee77b652e
Author: Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2024-03-18 20:57:00 +0000
Commit: Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2024-03-18 20:57:00 +0000
tcp: clear all TCP timers in tcp_timer_stop() when in callout
When a TCP callout decides to disable self, e.g. tcp_timer_2msl() calling
tcp_close(), we must also clear all other possible timers. Otherwise,
upon return, the callout would be scheduled again in tcp_timer_enter().
Revert 57e27ff07aff, which was a temporary partial revert of otherwise
correct 62d47d73b7eb, that exposed the problem being fixed now. Add an
extra assertion in tcp_timer_enter() to check we aren't arming callout for
a closed connection.
Reviewed by: rscheff
---
sys/netinet/tcp_subr.c | 3 +--
sys/netinet/tcp_timer.c | 6 ++++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index f618bc1ba04b..a6f84c297688 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2395,10 +2395,9 @@ tcp_discardcb(struct tcpcb *tp)
#endif
INP_WLOCK_ASSERT(inp);
+ MPASS(!callout_active(&tp->t_callout));
MPASS(TAILQ_EMPTY(&tp->snd_holes));
- tcp_timer_stop(tp);
-
/* free the reassembly queue, if any */
tcp_reass_flush(tp);
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index ed50659abf8e..785f68be5621 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -881,6 +881,7 @@ tcp_timer_enter(void *xtp)
if (tp_valid) {
tcp_bblog_timer(tp, which, TT_PROCESSED, 0);
if ((which = tcp_timer_next(tp, &precision)) != TT_N) {
+ MPASS(tp->t_state > TCPS_CLOSED);
callout_reset_sbt_on(&tp->t_callout,
tp->t_timers[which], precision, tcp_timer_enter,
tp, inp_to_cpuid(inp), C_ABSOLUTE);
@@ -939,8 +940,7 @@ tcp_timer_active(struct tcpcb *tp, tt_which which)
/*
* Stop all timers associated with tcpcb.
*
- * Called only on tcpcb destruction. The tcpcb shall already be dropped from
- * the pcb lookup database and socket is not losing the last reference.
+ * Called when tcpcb moves to TCPS_CLOSED.
*
* XXXGL: unfortunately our callout(9) is not able to fully stop a locked
* callout even when only two threads are involved: the callout itself and the
@@ -963,6 +963,8 @@ tcp_timer_stop(struct tcpcb *tp)
stopped = callout_stop(&tp->t_callout);
MPASS(stopped == 0);
+ for (tt_which i = 0; i < TT_N; i++)
+ tp->t_timers[i] = SBT_MAX;
} else while(__predict_false(callout_stop(&tp->t_callout) == 0)) {
INP_WUNLOCK(inp);
kern_yield(PRI_UNCHANGED);