tcp_timers: check for (INP_TIMEWAIT | INP_DROPPED) only once

All timers keep inpcb locked through their execution.  We need to
check these flags only once.  Checking for INP_TIMEWAIT earlier is
is also safer, since such inpcbs point into tcptw rather than tcpcb,
and any dereferences of inp_ppcb as tcpcb are erroneous.

Reviewed by:		rrs, hselasky
Differential revision:	https://reviews.freebsd.org/D32967
This commit is contained in:
Gleb Smirnoff 2021-11-09 21:22:54 -08:00
parent 5690261858
commit 9a06a82455

View File

@ -328,7 +328,7 @@ tcp_timer_2msl(void *xtp)
return; return;
} }
callout_deactivate(&tp->t_timers->tt_2msl); callout_deactivate(&tp->t_timers->tt_2msl);
if ((inp->inp_flags & INP_DROPPED) != 0) { if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
INP_WUNLOCK(inp); INP_WUNLOCK(inp);
CURVNET_RESTORE(); CURVNET_RESTORE();
return; return;
@ -341,26 +341,14 @@ tcp_timer_2msl(void *xtp)
* too long delete connection control block. Otherwise, check * too long delete connection control block. Otherwise, check
* again in a bit. * again in a bit.
* *
* If in TIME_WAIT state just ignore as this timeout is handled in
* tcp_tw_2msl_scan().
*
* If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed,
* there's no point in hanging onto FIN_WAIT_2 socket. Just close it. * there's no point in hanging onto FIN_WAIT_2 socket. Just close it.
* Ignore fact that there were recent incoming segments. * Ignore fact that there were recent incoming segments.
*/ */
if ((inp->inp_flags & INP_TIMEWAIT) != 0) {
INP_WUNLOCK(inp);
CURVNET_RESTORE();
return;
}
if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 &&
tp->t_inpcb && tp->t_inpcb->inp_socket && tp->t_inpcb && tp->t_inpcb->inp_socket &&
(tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) {
TCPSTAT_INC(tcps_finwait2_drops); TCPSTAT_INC(tcps_finwait2_drops);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
tcp_inpinfo_lock_del(inp, tp);
goto out;
}
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
tp = tcp_close(tp); tp = tcp_close(tp);
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);
@ -371,10 +359,6 @@ tcp_timer_2msl(void *xtp)
callout_reset(&tp->t_timers->tt_2msl, callout_reset(&tp->t_timers->tt_2msl,
TP_KEEPINTVL(tp), tcp_timer_2msl, tp); TP_KEEPINTVL(tp), tcp_timer_2msl, tp);
} else { } else {
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
tcp_inpinfo_lock_del(inp, tp);
goto out;
}
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
tp = tcp_close(tp); tp = tcp_close(tp);
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);
@ -419,7 +403,7 @@ tcp_timer_keep(void *xtp)
return; return;
} }
callout_deactivate(&tp->t_timers->tt_keep); callout_deactivate(&tp->t_timers->tt_keep);
if ((inp->inp_flags & INP_DROPPED) != 0) { if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
INP_WUNLOCK(inp); INP_WUNLOCK(inp);
CURVNET_RESTORE(); CURVNET_RESTORE();
return; return;
@ -498,10 +482,6 @@ tcp_timer_keep(void *xtp)
dropit: dropit:
TCPSTAT_INC(tcps_keepdrops); TCPSTAT_INC(tcps_keepdrops);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
tcp_inpinfo_lock_del(inp, tp);
goto out;
}
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
tp = tcp_drop(tp, ETIMEDOUT); tp = tcp_drop(tp, ETIMEDOUT);
@ -513,7 +493,6 @@ dropit:
TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO);
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);
tcp_inpinfo_lock_del(inp, tp); tcp_inpinfo_lock_del(inp, tp);
out:
CURVNET_RESTORE(); CURVNET_RESTORE();
} }
@ -539,7 +518,7 @@ tcp_timer_persist(void *xtp)
return; return;
} }
callout_deactivate(&tp->t_timers->tt_persist); callout_deactivate(&tp->t_timers->tt_persist);
if ((inp->inp_flags & INP_DROPPED) != 0) { if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
INP_WUNLOCK(inp); INP_WUNLOCK(inp);
CURVNET_RESTORE(); CURVNET_RESTORE();
return; return;
@ -562,10 +541,6 @@ tcp_timer_persist(void *xtp)
(ticks - tp->t_rcvtime >= tcp_maxpersistidle || (ticks - tp->t_rcvtime >= tcp_maxpersistidle ||
ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) {
TCPSTAT_INC(tcps_persistdrop); TCPSTAT_INC(tcps_persistdrop);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
tcp_inpinfo_lock_del(inp, tp);
goto out;
}
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
tp = tcp_drop(tp, ETIMEDOUT); tp = tcp_drop(tp, ETIMEDOUT);
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);
@ -579,10 +554,6 @@ tcp_timer_persist(void *xtp)
if (tp->t_state > TCPS_CLOSE_WAIT && if (tp->t_state > TCPS_CLOSE_WAIT &&
(ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) {
TCPSTAT_INC(tcps_persistdrop); TCPSTAT_INC(tcps_persistdrop);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
tcp_inpinfo_lock_del(inp, tp);
goto out;
}
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
tp = tcp_drop(tp, ETIMEDOUT); tp = tcp_drop(tp, ETIMEDOUT);
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);
@ -630,7 +601,7 @@ tcp_timer_rexmt(void * xtp)
return; return;
} }
callout_deactivate(&tp->t_timers->tt_rexmt); callout_deactivate(&tp->t_timers->tt_rexmt);
if ((inp->inp_flags & INP_DROPPED) != 0) { if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
INP_WUNLOCK(inp); INP_WUNLOCK(inp);
CURVNET_RESTORE(); CURVNET_RESTORE();
return; return;
@ -651,10 +622,6 @@ tcp_timer_rexmt(void * xtp)
if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
tp->t_rxtshift = TCP_MAXRXTSHIFT; tp->t_rxtshift = TCP_MAXRXTSHIFT;
TCPSTAT_INC(tcps_timeoutdrop); TCPSTAT_INC(tcps_timeoutdrop);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
tcp_inpinfo_lock_del(inp, tp);
goto out;
}
NET_EPOCH_ENTER(et); NET_EPOCH_ENTER(et);
tp = tcp_drop(tp, ETIMEDOUT); tp = tcp_drop(tp, ETIMEDOUT);
NET_EPOCH_EXIT(et); NET_EPOCH_EXIT(et);