Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Apr 2013 17:43:31 +0200
From:      Peter Holm <peter@holm.cc>
To:        Juan Mojica <jmojica@gmail.com>
Cc:        FreeBSD Net <freebsd-net@freebsd.org>, Rick Macklem <rmacklem@uoguelph.ca>, Andre Oppermann <andre@freebsd.org>, Matt Miller <matt@matthewjmiller.net>
Subject:   Re: panic in tcp_do_segment()
Message-ID:  <20130412154331.GA46423@x2.osted.lan>
In-Reply-To: <CAPKuH-zz_tARNUNs%2BHBsE3XVLk_-zvKxG8F2dG%2BUBeoRinb4XQ@mail.gmail.com>
References:  <1043692819.529554.1365114790772.JavaMail.root@erie.cs.uoguelph.ca> <CAFc6gu9bmJQ-Uxv7PzspSLDyFz6zE3fV=u7HEumCh6f=YQLU2Q@mail.gmail.com> <5162B474.6060808@freebsd.org> <20130409081652.GA50498@x2.osted.lan> <5163D2D2.2090407@freebsd.org> <20130409184439.GA62925@x2.osted.lan> <CAPKuH-zz_tARNUNs%2BHBsE3XVLk_-zvKxG8F2dG%2BUBeoRinb4XQ@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, Apr 12, 2013 at 10:14:40AM -0400, Juan Mojica wrote:

Glad I could help.

- Peter

>    I'm a little late to get back to the email thread, but this is great to
>    hear.  Changes look good (assuming the goto drop is changed
>    dropunlock).  Thanks guys.
> 
>    On Tue, Apr 9, 2013 at 2:44 PM, Peter Holm <[1]peter@holm.cc> wrote:
> 
>    On Tue, Apr 09, 2013 at 10:35:30AM +0200, Andre Oppermann wrote:
>    > On 09.04.2013 10:16, Peter Holm wrote:
>    > > On Mon, Apr 08, 2013 at 02:13:40PM +0200, Andre Oppermann wrote:
>    > >> On 05.04.2013 13:09, Matt Miller wrote:
>    > >>> Hey Rick,
>    > >>>
>    > >>> I believe Juan and I have root caused this crash recently.  The
>    t_state =
>    > >>> 0x1, TCPS_LISTEN, in the link provided at the time of the
>    assertion.
>    > >>>
>    > >>> In tcp_input(), if we're in TCPS_LISTEN, SO_ACCEPTCONN should be
>    set on the
>    > >>> socket and we should never enter tcp_do_segment() for this state.
>     I think
>    > >>> if you look in your corefile, you'll see the socket *doesn't*
>    have this
>    > >>> flag set in your case.
>    > >>>
>    > >>> 1043         /*
>    > >>> 1044          * When the socket is accepting connections (the
>    INPCB is in
>    > >>> LISTEN
>    > >>> 1045          * state) we look into the SYN cache if this is a
>    new
>    > >>> connection
>    > >>> 1046          * attempt or the completion of a previous one.
>    Because listen
>    > >>> 1047          * sockets are never in TCPS_ESTABLISHED, the
>    V_tcbinfo lock
>    > >>> will be
>    > >>> 1048          * held in this case.
>    > >>> 1049          */
>    > >>> 1050         if (so->so_options & SO_ACCEPTCONN) {
>    > >>> 1051                 struct in_conninfo inc;
>    > >>> 1052
>    > >>> 1053                 KASSERT(tp->t_state == TCPS_LISTEN, ("%s: so
>    accepting
>    > >>> but "
>    > >>> 1054                     "tp not listening", __func__));
>    > >>> ...
>    > >>> 1356                 syncache_add(&inc, &to, th, inp, &so, m,
>    NULL, NULL);
>    > >>> 1357                 /*
>    > >>> 1358                  * Entry added to syncache and mbuf
>    consumed.
>    > >>> 1359                  * Everything already unlocked by
>    syncache_add().
>    > >>> 1360                  */
>    > >>> 1361                 INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
>    > >>> 1362                 return;
>    > >>> 1363         }
>    > >>> ...
>    > >>> 1384         /*
>    > >>> 1385          * Segment belongs to a connection in SYN_SENT,
>    ESTABLISHED or
>    > >>> later
>    > >>> 1386          * state.  tcp_do_segment() always consumes the mbuf
>    chain,
>    > >>> unlocks
>    > >>> 1387          * the inpcb, and unlocks pcbinfo.
>    > >>> 1388          */
>    > >>> 1389         tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen,
>    iptos,
>    > >>> ti_locked);
>    > >>>
>    > >>> I think this has to do with this patch in soclose() where
>    SO_ACCEPTCONN is
>    > >>> being turned off in soclose().  I suspect if you look at the
>    other threads
>    > >>> in your corefile, you'll see one at this point in soclose()
>    operating on
>    > >>> the same socket as the one in the tcp_do_segment() thread.
>    > >>>
>    > >>> [2]http://svnweb.freebsd.org/base?view=revision&revision=243627
>    > >>>
>    > >>>    817                 /*
>    > >>>    818                  * Prevent new additions to the accept
>    queues due
>    > >>>    819                  * to ACCEPT_LOCK races while we are
>    draining them.
>    > >>>    820                  */
>    > >>>    821                 so->so_options &= ~SO_ACCEPTCONN;
>    > >>>    822                 while ((sp = TAILQ_FIRST(&so->so_incomp))
>    != NULL) {
>    > >>>    823                         TAILQ_REMOVE(&so->so_incomp, sp,
>    so_list);
>    > >>>    824                         so->so_incqlen--;
>    > >>>    825                         sp->so_qstate &= ~SQ_INCOMP;
>    > >>>    826                         sp->so_head = NULL;
>    > >>>    827                         ACCEPT_UNLOCK();
>    > >>>    828                         soabort(sp);
>    > >>>    829                         ACCEPT_LOCK();
>    > >>>    830                 }
>    > >>>
>    > >>> Juan had evaluated this code path and it seemed safe to just drop
>    the
>    > >>> packet in this case:
>    > >>>
>    > >>> +     /*
>    > >>> +      * In closing down the socket, the SO_ACCEPTCONN flag is
>    removed to
>    > >>> +      * prevent new connections from being established.  This
>    means that
>    > >>> +      * any frames in that were in the midst of being processed
>    could
>    > >>> +      * make it here.  Need to just drop the frame.
>    > >>> +      */
>    > >>> +     if (TCPS_LISTEN == tp->t_state) {
>    > >>> +         TCPSTAT_INC(tcps_rcvwhileclosing);
>    > >>> +         goto drop;
>    > >>> +     }
>    > >>>         KASSERT(tp->t_state > TCPS_LISTEN, ("%s: TCPS_LISTEN",
>    > >>>             __func__));
>    > >>>
>    > >>> Or, if there's someone more familiar with the locking in these
>    paths, they
>    > >>> may be able to come up with a way to restructure the locks and
>    logic to
>    > >>> close this window.
>    > >>
>    > >> Matt, Juan,
>    > >>
>    > >> excellent analysis.  I don't see a better approach to handle this
>    > >> under the current ACCEPT_LOCK model.
>    > >>
>    > >> Compared to your patch I'd like to handle this race earlier before
>    > >> we hit tcp_do_segment().
>    > >>
>    > >> Could you please review the attached patch which handles it right
>    > >> after the SO_ACCEPTCONN / syncache check?
>    > >>
>    > >> --
>    > >> Andre
>    > >>
>    > >> Index: netinet/tcp_input.c
>    > >>
>    ===================================================================
>    > >> --- netinet/tcp_input.c    (revision 249253)
>    > >> +++ netinet/tcp_input.c    (working copy)
>    > >> @@ -1351,6 +1351,16 @@
>    > >>                     */
>    > >>                    INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
>    > >>                    return;
>    > >> +  } else if (tp->t_state == TCPS_LISTEN) {
>    > >> +          /*
>    > >> +           * When a listen socket is torn down the SO_ACCEPTCONN
>    > >> +           * flag is removed first while connections are drained
>    > >> +           * from the accept queue in a unlock/lock cycle of the
>    > >> +           * ACCEPT_LOCK, opening a race condition allowing a SYN
>    > >> +           * attempt go through unhandled.
>    > >> +           */
>    > >> +          TCPSTAT_INC(tcps_rcvdwhileclosing);
>    > >> +          goto drop;
>    > >>            }
>    > >>
>    > >>    #ifdef TCP_SIGNATURE
>    > >
>    > > I was able to reproduce the original "panic: tcp_do_segment:
>    > > TCPS_LISTEN" with ease; see
>    > > [3]http://people.freebsd.org/~pho/stress/log/tcp.txt.
>    > >
>    > > With your patch (minus the TCPSTAT_INC) I got this "panic: Lock
>    (rw)
>    > > tcp locked @ netinet/tcp_input.c:1432."
>    > >
>    > > [4]http://people.freebsd.org/~pho/stress/log/tcp2.txt
>    >
>    > Please replace the 'goto drop' with 'goto dropunlock' to fix the
>    panic.
>    >
> 
>      Yes, this seems to take care of the two problems reported. Tested
>      for
>      5 hours without any repeats.
>      - Peter
> 
>    --
>    Juan Mojica
>    Email: [5]jmojica@gmail.com
> 
> References
> 
>    1. mailto:peter@holm.cc
>    2. http://svnweb.freebsd.org/base?view=revision&revision=243627
>    3. http://people.freebsd.org/~pho/stress/log/tcp.txt
>    4. http://people.freebsd.org/~pho/stress/log/tcp2.txt
>    5. mailto:jmojica@gmail.com



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130412154331.GA46423>