Index: head/sys/netinet/tcp_stacks/fastpath.c =================================================================== --- head/sys/netinet/tcp_stacks/fastpath.c +++ head/sys/netinet/tcp_stacks/fastpath.c @@ -2386,7 +2386,6 @@ NULL, NULL, NULL, - NULL, 0, 0 @@ -2403,7 +2402,6 @@ NULL, NULL, NULL, - NULL, 0, 0 }; Index: head/sys/netinet/tcp_subr.c =================================================================== --- head/sys/netinet/tcp_subr.c +++ head/sys/netinet/tcp_subr.c @@ -244,7 +244,6 @@ static void tcp_mtudisc(struct inpcb *, int); static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, const void *ip6hdr); -static void tcp_timer_discard(struct tcpcb *, uint32_t); static struct tcp_function_block tcp_def_funcblk = { @@ -258,7 +257,6 @@ NULL, NULL, NULL, - NULL, 0, 0 }; @@ -528,7 +526,6 @@ return (EINVAL); } if (blk->tfb_tcp_timer_stop_all || - blk->tfb_tcp_timers_left || blk->tfb_tcp_timer_activate || blk->tfb_tcp_timer_active || blk->tfb_tcp_timer_stop) { @@ -537,7 +534,6 @@ * must have them all. */ if ((blk->tfb_tcp_timer_stop_all == NULL) || - (blk->tfb_tcp_timers_left == NULL) || (blk->tfb_tcp_timer_activate == NULL) || (blk->tfb_tcp_timer_active == NULL) || (blk->tfb_tcp_timer_stop == NULL)) { @@ -1343,13 +1339,21 @@ * callout, and the last discard function called will take care of * deleting the tcpcb. */ + tp->t_timers->tt_draincnt = 0; tcp_timer_stop(tp, TT_REXMT); tcp_timer_stop(tp, TT_PERSIST); tcp_timer_stop(tp, TT_KEEP); tcp_timer_stop(tp, TT_2MSL); tcp_timer_stop(tp, TT_DELACK); if (tp->t_fb->tfb_tcp_timer_stop_all) { - /* Call the stop-all function of the methods */ + /* + * Call the stop-all function of the methods, + * this function should call the tcp_timer_stop() + * method with each of the function specific timeouts. + * That stop will be called via the tfb_tcp_timer_stop() + * which should use the async drain function of the + * callout system (see tcp_var.h). + */ tp->t_fb->tfb_tcp_timer_stop_all(tp); } @@ -1434,13 +1438,8 @@ CC_ALGO(tp) = NULL; inp->inp_ppcb = NULL; - if ((tp->t_timers->tt_flags & TT_MASK) == 0) { + if (tp->t_timers->tt_draincnt == 0) { /* We own the last reference on tcpcb, let's free it. */ - if ((tp->t_fb->tfb_tcp_timers_left) && - (tp->t_fb->tfb_tcp_timers_left(tp))) { - /* Some fb timers left running! */ - return; - } if (tp->t_fb->tfb_tcp_fb_fini) (*tp->t_fb->tfb_tcp_fb_fini)(tp); refcount_release(&tp->t_fb->tfb_refcnt); @@ -1453,45 +1452,12 @@ } void -tcp_timer_2msl_discard(void *xtp) -{ - - tcp_timer_discard((struct tcpcb *)xtp, TT_2MSL); -} - -void -tcp_timer_keep_discard(void *xtp) -{ - - tcp_timer_discard((struct tcpcb *)xtp, TT_KEEP); -} - -void -tcp_timer_persist_discard(void *xtp) -{ - - tcp_timer_discard((struct tcpcb *)xtp, TT_PERSIST); -} - -void -tcp_timer_rexmt_discard(void *xtp) -{ - - tcp_timer_discard((struct tcpcb *)xtp, TT_REXMT); -} - -void -tcp_timer_delack_discard(void *xtp) -{ - - tcp_timer_discard((struct tcpcb *)xtp, TT_DELACK); -} - -void -tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type) +tcp_timer_discard(void *ptp) { struct inpcb *inp; - + struct tcpcb *tp; + + tp = (struct tcpcb *)ptp; CURVNET_SET(tp->t_vnet); INP_INFO_RLOCK(&V_tcbinfo); inp = tp->t_inpcb; @@ -1500,16 +1466,9 @@ INP_WLOCK(inp); KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0, ("%s: tcpcb has to be stopped here", __func__)); - KASSERT((tp->t_timers->tt_flags & timer_type) != 0, - ("%s: discard callout should be running", __func__)); - tp->t_timers->tt_flags &= ~timer_type; - if ((tp->t_timers->tt_flags & TT_MASK) == 0) { + tp->t_timers->tt_draincnt--; + if (tp->t_timers->tt_draincnt == 0) { /* We own the last reference on this tcpcb, let's free it. */ - if ((tp->t_fb->tfb_tcp_timers_left) && - (tp->t_fb->tfb_tcp_timers_left(tp))) { - /* Some fb timers left running! */ - goto leave; - } if (tp->t_fb->tfb_tcp_fb_fini) (*tp->t_fb->tfb_tcp_fb_fini)(tp); refcount_release(&tp->t_fb->tfb_refcnt); @@ -1521,7 +1480,6 @@ return; } } -leave: INP_WUNLOCK(inp); INP_INFO_RUNLOCK(&V_tcbinfo); CURVNET_RESTORE(); Index: head/sys/netinet/tcp_timer.h =================================================================== --- head/sys/netinet/tcp_timer.h +++ head/sys/netinet/tcp_timer.h @@ -146,7 +146,7 @@ struct callout tt_2msl; /* 2*msl TIME_WAIT timer */ struct callout tt_delack; /* delayed ACK timer */ uint32_t tt_flags; /* Timers flags */ - uint32_t tt_spare; /* TDB */ + uint32_t tt_draincnt; /* Count being drained */ }; /* @@ -193,17 +193,13 @@ void tcp_timer_init(void); void tcp_timer_2msl(void *xtp); +void tcp_timer_discard(void *); struct tcptw * tcp_tw_2msl_scan(int reuse); /* XXX temporary? */ void tcp_timer_keep(void *xtp); void tcp_timer_persist(void *xtp); void tcp_timer_rexmt(void *xtp); void tcp_timer_delack(void *xtp); -void tcp_timer_2msl_discard(void *xtp); -void tcp_timer_keep_discard(void *xtp); -void tcp_timer_persist_discard(void *xtp); -void tcp_timer_rexmt_discard(void *xtp); -void tcp_timer_delack_discard(void *xtp); void tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer, struct xtcp_timer *xtimer); Index: head/sys/netinet/tcp_timer.c =================================================================== --- head/sys/netinet/tcp_timer.c +++ head/sys/netinet/tcp_timer.c @@ -927,7 +927,6 @@ tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) { struct callout *t_callout; - timeout_t *f_callout; uint32_t f_reset; tp->t_timers->tt_flags |= TT_STOPPED; @@ -935,27 +934,22 @@ switch (timer_type) { case TT_DELACK: t_callout = &tp->t_timers->tt_delack; - f_callout = tcp_timer_delack_discard; f_reset = TT_DELACK_RST; break; case TT_REXMT: t_callout = &tp->t_timers->tt_rexmt; - f_callout = tcp_timer_rexmt_discard; f_reset = TT_REXMT_RST; break; case TT_PERSIST: t_callout = &tp->t_timers->tt_persist; - f_callout = tcp_timer_persist_discard; f_reset = TT_PERSIST_RST; break; case TT_KEEP: t_callout = &tp->t_timers->tt_keep; - f_callout = tcp_timer_keep_discard; f_reset = TT_KEEP_RST; break; case TT_2MSL: t_callout = &tp->t_timers->tt_2msl; - f_callout = tcp_timer_2msl_discard; f_reset = TT_2MSL_RST; break; default: @@ -971,21 +965,13 @@ } if (tp->t_timers->tt_flags & timer_type) { - if ((callout_stop(t_callout) > 0) && - (tp->t_timers->tt_flags & f_reset)) { - tp->t_timers->tt_flags &= ~(timer_type | f_reset); - } else { + if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { /* * Can't stop the callout, defer tcpcb actual deletion - * to the last tcp timer discard callout. - * The TT_STOPPED flag will ensure that no tcp timer - * callouts can be restarted on our behalf, and - * past this point currently running callouts waiting - * on inp lock will return right away after the - * classical check for callout reset/stop events: - * callout_pending() || !callout_active() + * to the last one. We do this using the async drain + * function and incrementing the count in */ - callout_reset(t_callout, 1, f_callout, tp); + tp->t_timers->tt_draincnt++; } } } Index: head/sys/netinet/tcp_var.h =================================================================== --- head/sys/netinet/tcp_var.h +++ head/sys/netinet/tcp_var.h @@ -106,6 +106,17 @@ struct sockopt; struct socket; +/* + * If defining the optional tcp_timers, in the + * tfb_tcp_timer_stop call you must use the + * callout_async_drain() function with the + * tcp_timer_discard callback. You should check + * the return of callout_async_drain() and if 0 + * increment tt_draincnt. Since the timer sub-system + * does not know your callbacks you must provide a + * stop_all function that loops through and calls + * tcp_timer_stop() with each of your defined timers. + */ struct tcp_function_block { char tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX]; int (*tfb_tcp_output)(struct tcpcb *); @@ -120,7 +131,6 @@ void (*tfb_tcp_fb_fini)(struct tcpcb *); /* Optional timers, must define all if you define one */ int (*tfb_tcp_timer_stop_all)(struct tcpcb *); - int (*tfb_tcp_timers_left)(struct tcpcb *); void (*tfb_tcp_timer_activate)(struct tcpcb *, uint32_t, u_int); int (*tfb_tcp_timer_active)(struct tcpcb *, uint32_t);