From owner-p4-projects@FreeBSD.ORG Fri Sep 7 18:32:29 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id EB56716A41B; Fri, 7 Sep 2007 18:32:28 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9E78816A417 for ; Fri, 7 Sep 2007 18:32:28 +0000 (UTC) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 91EED13C458 for ; Fri, 7 Sep 2007 18:32:28 +0000 (UTC) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l87IWSqE059929 for ; Fri, 7 Sep 2007 18:32:28 GMT (envelope-from marcel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l87IWSG1059920 for perforce@freebsd.org; Fri, 7 Sep 2007 18:32:28 GMT (envelope-from marcel@freebsd.org) Date: Fri, 7 Sep 2007 18:32:28 GMT Message-Id: <200709071832.l87IWSG1059920@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar To: Perforce Change Reviews Cc: Subject: PERFORCE change 126159 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Sep 2007 18:32:29 -0000 http://perforce.freebsd.org/chv.cgi?CH=126159 Change 126159 by marcel@marcel_xcllnt on 2007/09/07 18:31:49 IFC @126158 Affected files ... .. //depot/projects/usiii/dev/usb/if_zyd.c#2 integrate .. //depot/projects/usiii/netinet/tcp_subr.c#2 integrate .. //depot/projects/usiii/netinet/tcp_timer.c#2 integrate .. //depot/projects/usiii/netinet/tcp_timer.h#2 integrate .. //depot/projects/usiii/netinet/tcp_usrreq.c#2 integrate .. //depot/projects/usiii/netinet/tcp_var.h#2 integrate Differences ... ==== //depot/projects/usiii/dev/usb/if_zyd.c#2 (text+ko) ==== @@ -1,6 +1,6 @@ /* $OpenBSD: if_zyd.c,v 1.52 2007/02/11 00:08:04 jsg Exp $ */ /* $NetBSD: if_zyd.c,v 1.7 2007/06/21 04:04:29 kiyohara Exp $ */ -/* $FreeBSD: src/sys/dev/usb/if_zyd.c,v 1.2 2007/09/05 23:40:59 sam Exp $ */ +/* $FreeBSD: src/sys/dev/usb/if_zyd.c,v 1.3 2007/09/07 03:54:54 sam Exp $ */ /*- * Copyright (c) 2006 by Damien Bergamini @@ -271,6 +271,7 @@ static int zyd_attach(device_t dev) { + int error = ENXIO; struct zyd_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); usb_device_descriptor_t* ddesc; @@ -293,7 +294,7 @@ device_printf(dev, "device version mismatch: 0x%x " "(only >= 43.30 supported)\n", UGETW(ddesc->bcdDevice)); - return -1; + goto bad; } ifp->if_softc = sc; @@ -307,7 +308,12 @@ STAILQ_INIT(&sc->sc_rqh); - zyd_attachhook(sc); + error = zyd_attachhook(sc); + if (error != 0) { +bad: + if_free(ifp); + return error; + } return 0; } @@ -332,6 +338,7 @@ error = usbd_set_config_no(sc->sc_udev, ZYD_CONFIG_NO, 1); if (error != 0) { device_printf(sc->sc_dev, "setting config no failed\n"); + error = ENXIO; goto fail; } @@ -339,6 +346,7 @@ &sc->sc_iface); if (error != 0) { device_printf(sc->sc_dev, "getting interface handle failed\n"); + error = ENXIO; goto fail; } @@ -522,7 +530,7 @@ return 0; fail: zyd_close_pipes(sc); - return error; + return ENXIO; } static void ==== //depot/projects/usiii/netinet/tcp_subr.c#2 (text+ko) ==== @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 - * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.296 2007/08/16 01:35:55 qingli Exp $ + * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.297 2007/09/07 09:19:22 rwatson Exp $ */ #include "opt_compat.h" @@ -214,7 +214,8 @@ */ struct tcpcb_mem { struct tcpcb tcb; - struct tcp_timer tt; + struct callout tcpcb_mem_rexmt, tcpcb_mem_persist, tcpcb_mem_keep; + struct callout tcpcb_mem_2msl, tcpcb_mem_delack; }; static uma_zone_t tcpcb_zone; @@ -589,7 +590,6 @@ if (tm == NULL) return (NULL); tp = &tm->tcb; - tp->t_timers = &tm->tt; /* LIST_INIT(&tp->t_segq); */ /* XXX covered by M_ZERO */ tp->t_maxseg = tp->t_maxopd = #ifdef INET6 @@ -598,8 +598,11 @@ tcp_mssdflt; /* Set up our timeouts. */ - callout_init_mtx(&tp->t_timers->tt_timer, &inp->inp_mtx, - CALLOUT_RETURNUNLOCKED); + callout_init(tp->tt_rexmt = &tm->tcpcb_mem_rexmt, CALLOUT_MPSAFE); + callout_init(tp->tt_persist = &tm->tcpcb_mem_persist, CALLOUT_MPSAFE); + callout_init(tp->tt_keep = &tm->tcpcb_mem_keep, CALLOUT_MPSAFE); + callout_init(tp->tt_2msl = &tm->tcpcb_mem_2msl, CALLOUT_MPSAFE); + callout_init(tp->tt_delack = &tm->tcpcb_mem_delack, CALLOUT_MPSAFE); if (tcp_do_rfc1323) tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); @@ -671,15 +674,12 @@ /* * Make sure that all of our timers are stopped before we * delete the PCB. - * - * XXX: callout_stop() may race and a callout may already - * try to obtain the INP_LOCK. Only callout_drain() would - * stop this but it would cause a LOR thus we can't use it. - * The tcp_timer() function contains a lot of checks to - * handle this case rather gracefully. */ - tp->t_timers->tt_active = 0; - callout_stop(&tp->t_timers->tt_timer); + callout_stop(tp->tt_rexmt); + callout_stop(tp->tt_persist); + callout_stop(tp->tt_keep); + callout_stop(tp->tt_2msl); + callout_stop(tp->tt_delack); /* * If we got enough samples through the srtt filter, ==== //depot/projects/usiii/netinet/tcp_timer.c#2 (text+ko) ==== @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 - * $FreeBSD: src/sys/netinet/tcp_timer.c,v 1.95 2007/06/09 17:49:39 andre Exp $ + * $FreeBSD: src/sys/netinet/tcp_timer.c,v 1.96 2007/09/07 09:19:22 rwatson Exp $ */ #include "opt_inet6.h" @@ -35,9 +35,7 @@ #include #include -#include #include -#include #include #include #include @@ -115,20 +113,13 @@ /* max idle time in persist */ int tcp_maxidle; -static void tcp_timer(void *); -static int tcp_timer_delack(struct tcpcb *, struct inpcb *); -static int tcp_timer_2msl(struct tcpcb *, struct inpcb *); -static int tcp_timer_keep(struct tcpcb *, struct inpcb *); -static int tcp_timer_persist(struct tcpcb *, struct inpcb *); -static int tcp_timer_rexmt(struct tcpcb *, struct inpcb *); - /* * Tcp protocol timeout routine called every 500 ms. * Updates timestamps used for TCP * causes finite state machine actions if timers expire. */ void -tcp_slowtimo(void) +tcp_slowtimo() { tcp_maxidle = tcp_keepcnt * tcp_keepintvl; @@ -149,301 +140,82 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_race, CTLFLAG_RD, &tcp_timer_race, 0, "Count of t_inpcb races on tcp_discardcb"); +/* + * TCP timer processing. + */ + void -tcp_timer_activate(struct tcpcb *tp, int timer_type, u_int delta) +tcp_timer_delack(void *xtp) { - struct inpcb *inp = tp->t_inpcb; - struct tcp_timer *tt = tp->t_timers; - int tick = ticks; /* Stable time base. */ - int next = delta ? tick + delta : 0; + struct tcpcb *tp = xtp; + struct inpcb *inp; - INP_LOCK_ASSERT(inp); - - CTR6(KTR_NET, "%p %s inp %p active %x delta %i nextc %i", - tp, __func__, inp, tt->tt_active, delta, tt->tt_nextc); - - /* Set new value for timer. */ - switch(timer_type) { - case TT_DELACK: - CTR4(KTR_NET, "%p %s TT_DELACK old %i new %i", - tp, __func__, tt->tt_delack, next); - tt->tt_delack = next; - break; - case TT_REXMT: - CTR4(KTR_NET, "%p %s TT_REXMT old %i new %i", - tp, __func__, tt->tt_rexmt, next); - tt->tt_rexmt = next; - break; - case TT_PERSIST: - CTR4(KTR_NET, "%p %s TT_PERSIST old %i new %i", - tp, __func__, tt->tt_persist, next); - tt->tt_persist = next; - break; - case TT_KEEP: - CTR4(KTR_NET, "%p %s TT_KEEP old %i new %i", - tp, __func__, tt->tt_keep, next); - tt->tt_keep = next; - break; - case TT_2MSL: - CTR4(KTR_NET, "%p %s TT_2MSL old %i new %i", - tp, __func__, tt->tt_2msl, next); - tt->tt_2msl = next; - break; - case 0: /* Dummy for timer rescan. */ - CTR3(KTR_NET, "%p %s timer rescan new %i", tp, __func__, next); - break; - } - - /* If some other timer is active and is schedules sooner just return. */ - if (tt->tt_active != timer_type && tt->tt_nextc < next && - callout_active(&tt->tt_timer)) - return; - - /* Select next timer to schedule. */ - tt->tt_nextc = INT_MAX; - tt->tt_active = 0; - if (tt->tt_delack && tt->tt_delack < tt->tt_nextc) { - tt->tt_nextc = tt->tt_delack; - tt->tt_active = TT_DELACK; - } - if (tt->tt_rexmt && tt->tt_rexmt < tt->tt_nextc) { - tt->tt_nextc = tt->tt_rexmt; - tt->tt_active = TT_REXMT; - } - if (tt->tt_persist && tt->tt_persist < tt->tt_nextc) { - tt->tt_nextc = tt->tt_persist; - tt->tt_active = TT_PERSIST; - } - if (tt->tt_keep && tt->tt_keep < tt->tt_nextc) { - tt->tt_nextc = tt->tt_keep; - tt->tt_active = TT_KEEP; - } - if (tt->tt_2msl && tt->tt_2msl < tt->tt_nextc) { - tt->tt_nextc = tt->tt_2msl; - tt->tt_active = TT_2MSL; - } - - /* Rearm callout with new timer if we found one. */ - if (tt->tt_active) { - CTR4(KTR_NET, "%p %s callout_reset active %x nextc in %i", - tp, __func__, tt->tt_active, tt->tt_nextc - tick); - callout_reset(&tt->tt_timer, - tt->tt_nextc - tick, tcp_timer, (void *)inp); - } else { - CTR2(KTR_NET, "%p %s callout_stop", tp, __func__); - callout_stop(&tt->tt_timer); - tt->tt_nextc = 0; - } - - return; -} - -int -tcp_timer_active(struct tcpcb *tp, int timer_type) -{ - - switch (timer_type) { - case TT_DELACK: - CTR3(KTR_NET, "%p %s TT_DELACK %i", - tp, __func__, tp->t_timers->tt_delack); - return (tp->t_timers->tt_delack ? 1 : 0); - break; - case TT_REXMT: - CTR3(KTR_NET, "%p %s TT_REXMT %i", - tp, __func__, tp->t_timers->tt_rexmt); - return (tp->t_timers->tt_rexmt ? 1 : 0); - break; - case TT_PERSIST: - CTR3(KTR_NET, "%p %s TT_PERSIST %i", - tp, __func__, tp->t_timers->tt_persist); - return (tp->t_timers->tt_persist ? 1 : 0); - break; - case TT_KEEP: - CTR3(KTR_NET, "%p %s TT_KEEP %i", - tp, __func__, tp->t_timers->tt_keep); - return (tp->t_timers->tt_keep ? 1 : 0); - break; - case TT_2MSL: - CTR3(KTR_NET, "%p %s TT_2MSL %i", - tp, __func__, tp->t_timers->tt_2msl); - return (tp->t_timers->tt_2msl ? 1 : 0); - break; - } - return (0); -} - -static void -tcp_timer(void *xinp) -{ - struct inpcb *inp = (struct inpcb *)xinp; - struct tcpcb *tp = intotcpcb(inp); - struct tcp_timer *tt; - int tick = ticks; - int down, timer; - - /* INP lock was obtained by callout. */ - INP_LOCK_ASSERT(inp); - + INP_INFO_RLOCK(&tcbinfo); + inp = tp->t_inpcb; /* - * We've got a couple of race conditions here: - * - The tcpcb was converted into a compressed TW pcb. All our - * timers have been stopped while this callout already tried - * to obtain the inpcb lock. TW pcbs have their own timers - * and we just return. + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_delack: inp == NULL")); */ - if (inp->inp_vflag & INP_TIMEWAIT) + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_RUNLOCK(&tcbinfo); return; - /* - * - The tcpcb was discarded. All our timers have been stopped - * while this callout already tried to obtain the inpcb lock - * and we just return. - */ - if (tp == NULL) - return; - - tt = tp->t_timers; /* Initialize. */ - CTR6(KTR_NET, "%p %s inp %p active %x tick %i nextc %i", - tp, __func__, inp, tt->tt_active, tick, tt->tt_nextc); - - /* - * - We may have been waiting on the lock while the tcpcb has - * been scheduled for destruction. In this case no active - * timers remain and we just return. - */ - if (tt->tt_active == 0) - goto done; - - /* - * - The timer was rescheduled while this callout was already - * waiting on the lock. This may happen when a packet just - * came in. Rescan and reschedule the the timer in case we - * just turned it off. - */ - if (tick < tt->tt_nextc) - goto rescan; - - /* - * Mark as done. The active bit in struct callout is not - * automatically cleared. See callout(9) for more info. - * In tcp_discardcb() we depend on the correctly cleared - * active bit for faster processing. - */ - callout_deactivate(&tt->tt_timer); - - /* Check which timer has fired and remove this timer activation. */ - timer = tt->tt_active; - tt->tt_active = 0; - tt->tt_nextc = 0; - - switch (timer) { - case TT_DELACK: - CTR2(KTR_NET, "%p %s running TT_DELACK", tp, __func__); - tt->tt_delack = 0; - down = tcp_timer_delack(tp, inp); /* down == 0 */ - break; - case TT_REXMT: - CTR2(KTR_NET, "%p %s running TT_REXMT", tp, __func__); - tt->tt_rexmt = 0; - down = tcp_timer_rexmt(tp, inp); - break; - case TT_PERSIST: - CTR2(KTR_NET, "%p %s running TT_PERSIST", tp, __func__); - tt->tt_persist = 0; - down = tcp_timer_persist(tp, inp); - break; - case TT_KEEP: - CTR2(KTR_NET, "%p %s running TT_KEEP", tp, __func__); - tt->tt_keep = 0; - down = tcp_timer_keep(tp, inp); - break; - case TT_2MSL: - CTR2(KTR_NET, "%p %s running TT_2MSL", tp, __func__); - tt->tt_2msl = 0; - down = tcp_timer_2msl(tp, inp); - break; - default: - CTR2(KTR_NET, "%p %s running nothing", tp, __func__); - down = 0; } - - CTR4(KTR_NET, "%p %s down %i active %x", - tp, __func__, down, tt->tt_active); - /* Do we still exist? */ - if (down) - goto shutdown; - -rescan: - /* Rescan if no timer was reactivated above. */ - if (tt->tt_active == 0) - tcp_timer_activate(tp, 0, 0); - -done: - INP_UNLOCK(inp); /* CALLOUT_RETURNUNLOCKED */ - return; - -shutdown: - INP_UNLOCK(inp); /* Prevent LOR at expense of race. */ - INP_INFO_WLOCK(&tcbinfo); INP_LOCK(inp); - - /* - * XXX: When our tcpcb went into TIMEWAIT, is gone or no - * longer the one we used to work with we've lost the race. - * This race is inherent in the current socket/inpcb life - * cycle system. - */ - if ((inp->inp_vflag & INP_TIMEWAIT) || inp->inp_ppcb == NULL || - inp->inp_ppcb != tp) { - CTR3(KTR_NET, "%p %s inp %p lost shutdown race", - tp, __func__, inp); - tcp_timer_race++; - INP_UNLOCK(inp); /* CALLOUT_RETURNUNLOCKED */ - INP_INFO_WUNLOCK(&tcbinfo); + INP_INFO_RUNLOCK(&tcbinfo); + if ((inp->inp_vflag & INP_DROPPED) || callout_pending(tp->tt_delack) + || !callout_active(tp->tt_delack)) { + INP_UNLOCK(inp); return; } - KASSERT(tp == inp->inp_ppcb, ("%s: tp changed", __func__)); - - /* Shutdown the connection. */ - switch (down) { - case 1: - tp = tcp_close(tp); - break; - case 2: - tp = tcp_drop(tp, - tp->t_softerror ? tp->t_softerror : ETIMEDOUT); - break; - } - CTR3(KTR_NET, "%p %s inp %p after shutdown", tp, __func__, inp); + callout_deactivate(tp->tt_delack); - if (tp) - INP_UNLOCK(inp); /* CALLOUT_RETURNUNLOCKED */ - - INP_INFO_WUNLOCK(&tcbinfo); - return; -} - -/* - * TCP timer processing. - */ -static int -tcp_timer_delack(struct tcpcb *tp, struct inpcb *inp) -{ - tp->t_flags |= TF_ACKNOW; tcpstat.tcps_delack++; (void) tcp_output(tp); - return (0); + INP_UNLOCK(inp); } -static int -tcp_timer_2msl(struct tcpcb *tp, struct inpcb *inp) +void +tcp_timer_2msl(void *xtp) { + struct tcpcb *tp = xtp; + struct inpcb *inp; #ifdef TCPDEBUG int ostate; ostate = tp->t_state; #endif /* + * XXXRW: Does this actually happen? + */ + INP_INFO_WLOCK(&tcbinfo); + inp = tp->t_inpcb; + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_2msl: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + INP_LOCK(inp); + tcp_free_sackholes(tp); + if ((inp->inp_vflag & INP_DROPPED) || callout_pending(tp->tt_2msl) || + !callout_active(tp->tt_2msl)) { + INP_UNLOCK(tp->t_inpcb); + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + callout_deactivate(tp->tt_2msl); + /* * 2 MSL timeout in shutdown went off. If we're closed but * still waiting for peer to close and connection has been idle * too long, or if 2MSL time is up from TIME_WAIT, delete connection @@ -454,35 +226,62 @@ * Ignore fact that there were recent incoming segments. */ if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && - tp->t_inpcb->inp_socket && + tp->t_inpcb && tp->t_inpcb->inp_socket && (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { tcpstat.tcps_finwait2_drops++; - return (1); /* tcp_close */ + tp = tcp_close(tp); } else { if (tp->t_state != TCPS_TIME_WAIT && (ticks - tp->t_rcvtime) <= tcp_maxidle) - tcp_timer_activate(tp, TT_2MSL, tcp_keepintvl); - else - return (1); /* tcp_close */ - } + callout_reset(tp->tt_2msl, tcp_keepintvl, + tcp_timer_2msl, tp); + else + tp = tcp_close(tp); + } #ifdef TCPDEBUG if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - return (0); + if (tp != NULL) + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); } -static int -tcp_timer_keep(struct tcpcb *tp, struct inpcb *inp) +void +tcp_timer_keep(void *xtp) { + struct tcpcb *tp = xtp; struct tcptemp *t_template; + struct inpcb *inp; #ifdef TCPDEBUG int ostate; ostate = tp->t_state; #endif + INP_INFO_WLOCK(&tcbinfo); + inp = tp->t_inpcb; + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_keep: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + INP_LOCK(inp); + if ((inp->inp_vflag & INP_DROPPED) || callout_pending(tp->tt_keep) + || !callout_active(tp->tt_keep)) { + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + callout_deactivate(tp->tt_keep); /* * Keep-alive timer went off; send something * or drop connection if idle for too long. @@ -514,30 +313,65 @@ tp->rcv_nxt, tp->snd_una - 1, 0); (void) m_free(dtom(t_template)); } - tcp_timer_activate(tp, TT_KEEP, tcp_keepintvl); + callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp); } else - tcp_timer_activate(tp, TT_KEEP, tcp_keepidle); + callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp); #ifdef TCPDEBUG if (inp->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - return (0); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return; dropit: tcpstat.tcps_keepdrops++; - return (2); /* tcp_drop() */ + tp = tcp_drop(tp, ETIMEDOUT); + +#ifdef TCPDEBUG + if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); +#endif + if (tp != NULL) + INP_UNLOCK(tp->t_inpcb); + INP_INFO_WUNLOCK(&tcbinfo); } -static int -tcp_timer_persist(struct tcpcb *tp, struct inpcb *inp) +void +tcp_timer_persist(void *xtp) { + struct tcpcb *tp = xtp; + struct inpcb *inp; #ifdef TCPDEBUG int ostate; ostate = tp->t_state; #endif + INP_INFO_WLOCK(&tcbinfo); + inp = tp->t_inpcb; + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_persist: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + INP_LOCK(inp); + if ((inp->inp_vflag & INP_DROPPED) || callout_pending(tp->tt_persist) + || !callout_active(tp->tt_persist)) { + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + callout_deactivate(tp->tt_persist); /* * Persistance timer into zero window. * Force a byte to be output, if possible. @@ -554,29 +388,59 @@ ((ticks - tp->t_rcvtime) >= tcp_maxpersistidle || (ticks - tp->t_rcvtime) >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { tcpstat.tcps_persistdrop++; - return (2); /* tcp_drop() */ + tp = tcp_drop(tp, ETIMEDOUT); + goto out; } tcp_setpersist(tp); tp->t_flags |= TF_FORCEDATA; (void) tcp_output(tp); tp->t_flags &= ~TF_FORCEDATA; +out: #ifdef TCPDEBUG if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); #endif - return (0); + if (tp != NULL) + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); } -static int -tcp_timer_rexmt(struct tcpcb *tp, struct inpcb *inp) +void +tcp_timer_rexmt(void * xtp) { + struct tcpcb *tp = xtp; int rexmt; + int headlocked; + struct inpcb *inp; #ifdef TCPDEBUG int ostate; ostate = tp->t_state; #endif + INP_INFO_WLOCK(&tcbinfo); + headlocked = 1; + inp = tp->t_inpcb; + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_rexmt: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + INP_LOCK(inp); + if ((inp->inp_vflag & INP_DROPPED) || callout_pending(tp->tt_rexmt) + || !callout_active(tp->tt_rexmt)) { + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return; + } + callout_deactivate(tp->tt_rexmt); tcp_free_sackholes(tp); /* * Retransmission timer went off. Message has not @@ -586,8 +450,12 @@ if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { tp->t_rxtshift = TCP_MAXRXTSHIFT; tcpstat.tcps_timeoutdrop++; - return (2); /* tcp_drop() */ + tp = tcp_drop(tp, tp->t_softerror ? + tp->t_softerror : ETIMEDOUT); + goto out; } + INP_INFO_WUNLOCK(&tcbinfo); + headlocked = 0; if (tp->t_rxtshift == 1) { /* * first retransmit; record ssthresh and cwnd so they can @@ -602,9 +470,9 @@ tp->snd_ssthresh_prev = tp->snd_ssthresh; tp->snd_recover_prev = tp->snd_recover; if (IN_FASTRECOVERY(tp)) - tp->t_flags |= TF_WASFRECOVERY; + tp->t_flags |= TF_WASFRECOVERY; else - tp->t_flags &= ~TF_WASFRECOVERY; + tp->t_flags &= ~TF_WASFRECOVERY; tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); } tcpstat.tcps_rexmttimeo++; @@ -683,10 +551,78 @@ EXIT_FASTRECOVERY(tp); (void) tcp_output(tp); +out: #ifdef TCPDEBUG if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - return (0); + if (tp != NULL) + INP_UNLOCK(inp); + if (headlocked) + INP_INFO_WUNLOCK(&tcbinfo); +} + +void +tcp_timer_activate(struct tcpcb *tp, int timer_type, u_int delta) +{ + struct callout *t_callout; + void *f_callout; + + switch (timer_type) { + case TT_DELACK: + t_callout = tp->tt_delack; + f_callout = tcp_timer_delack; + break; + case TT_REXMT: + t_callout = tp->tt_rexmt; + f_callout = tcp_timer_rexmt; + break; + case TT_PERSIST: + t_callout = tp->tt_persist; + f_callout = tcp_timer_persist; + break; + case TT_KEEP: + t_callout = tp->tt_keep; + f_callout = tcp_timer_keep; + break; + case TT_2MSL: + t_callout = tp->tt_2msl; + f_callout = tcp_timer_2msl; + break; + default: + panic("bad timer_type"); + } + if (delta == 0) { + callout_stop(t_callout); + } else { + callout_reset(t_callout, delta, f_callout, tp); + } +} + +int +tcp_timer_active(struct tcpcb *tp, int timer_type) +{ + struct callout *t_callout; + + switch (timer_type) { + case TT_DELACK: + t_callout = tp->tt_delack; + break; + case TT_REXMT: + t_callout = tp->tt_rexmt; + break; + case TT_PERSIST: + t_callout = tp->tt_persist; + break; + case TT_KEEP: + t_callout = tp->tt_keep; + break; + case TT_2MSL: + t_callout = tp->tt_2msl; + break; + default: + panic("bad timer_type"); + } + return callout_active(t_callout); } ==== //depot/projects/usiii/netinet/tcp_timer.h#2 (text+ko) ==== @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: src/sys/netinet/tcp_timer.h,v 1.37 2007/07/31 22:11:55 peter Exp $ + * $FreeBSD: src/sys/netinet/tcp_timer.h,v 1.38 2007/09/07 09:19:22 rwatson Exp $ */ #ifndef _NETINET_TCP_TIMER_H_ @@ -141,21 +141,11 @@ #ifdef _KERNEL -struct tcp_timer { - struct callout tt_timer; - int tt_nextc; /* next callout time in time_uptime */ - int tt_active; /* engaged callouts */ #define TT_DELACK 0x01 #define TT_REXMT 0x02 #define TT_PERSIST 0x04 #define TT_KEEP 0x08 #define TT_2MSL 0x10 - int tt_delack; - int tt_rexmt; - int tt_persist; - int tt_keep; - int tt_2msl; -}; extern int tcp_keepinit; /* time to establish connection */ extern int tcp_keepidle; /* time before keepalive probes begin */ @@ -173,8 +163,13 @@ extern int tcp_fast_finwait2_recycle; void tcp_timer_init(void); +void tcp_timer_2msl(void *xtp); 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); #endif /* _KERNEL */ ==== //depot/projects/usiii/netinet/tcp_usrreq.c#2 (text+ko) ==== @@ -29,7 +29,7 @@ * SUCH DAMAGE. * * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 - * $FreeBSD: src/sys/netinet/tcp_usrreq.c,v 1.160 2007/07/30 11:06:41 des Exp $ + * $FreeBSD: src/sys/netinet/tcp_usrreq.c,v 1.161 2007/09/07 09:19:22 rwatson Exp $ */ #include "opt_ddb.h" @@ -1743,15 +1743,12 @@ LIST_FIRST(&tp->t_segq), tp->t_segqlen, tp->t_dupacks); db_print_indent(indent); - db_printf("t_inpcb: %p t_timers: %p tt_active: %x\n", - tp->t_inpcb, tp->t_timers, tp->t_timers->tt_active); + db_printf("tt_rexmt: %p tt_persist: %p tt_keep: %p\n", + tp->tt_rexmt, tp->tt_persist, tp->tt_keep); db_print_indent(indent); - db_printf("tt_delack: %i tt_rexmt: %i tt_keep: %i " - "tt_persist: %i tt_2msl: %i\n", - tp->t_timers->tt_delack, tp->t_timers->tt_rexmt, - tp->t_timers->tt_keep, tp->t_timers->tt_persist, - tp->t_timers->tt_2msl); + db_printf("tt_2msl: %p tt_delack: %p t_inpcb: %p\n", tp->tt_2msl, + tp->tt_delack, tp->t_inpcb); db_print_indent(indent); db_printf("t_state: %d (", tp->t_state); ==== //depot/projects/usiii/netinet/tcp_var.h#2 (text+ko) ==== @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)tcp_var.h 8.4 (Berkeley) 5/24/95 - * $FreeBSD: src/sys/netinet/tcp_var.h,v 1.155 2007/07/28 12:20:39 andre Exp $ + * $FreeBSD: src/sys/netinet/tcp_var.h,v 1.156 2007/09/07 09:19:22 rwatson Exp $ */ #ifndef _NETINET_TCP_VAR_H_ @@ -96,7 +96,11 @@ int t_segqlen; /* segment reassembly queue length */ int t_dupacks; /* consecutive dup acks recd */ - struct tcp_timer *t_timers; /* retransmit timer */ + struct callout *tt_rexmt; /* retransmit timer */ + struct callout *tt_persist; /* retransmit persistence */ + struct callout *tt_keep; /* keepalive */ + struct callout *tt_2msl; /* 2*msl TIME_WAIT timer */ + struct callout *tt_delack; /* delayed ACK timer */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ int t_state; /* state of this connection */