On 01.09.2010 01:13, ben wilber wrote:
Hi,

I just upgraded from r210042 to r212073 and keep getting the panic
introduced in r211317:

panic: tcp_output: len<= tso_segsz

Please try the attached patch and report back whether it
fixes the issue.

I'm a bit in a hurry right now and can respond again later
in the evening.

--
Andre

db:0:kdb.enter.default>   bt
Tracing pid 12 tid 100063 td 0xffffff001881b000
kdb_enter() at kdb_enter+0x3d
panic() at panic+0x1c8
tcp_output() at tcp_output+0x1445
tcp_do_segment() at tcp_do_segment+0x252d
tcp_input() at tcp_input+0x1044
ip_input() at ip_input+0x5cd
netisr_dispatch_src() at netisr_dispatch_src+0xc1
netisr_dispatch() at netisr_dispatch+0x11
ether_demux() at ether_demux+0x19a
ether_input() at ether_input+0x36a
mxge_intr() at mxge_intr+0x5be
intr_event_execute_handlers() at intr_event_execute_handlers+0x107
ithread_loop() at ithread_loop+0xb5
fork_exit() at fork_exit+0x147
fork_trampoline() at fork_trampoline+0xe
--- trap 0, rip = 0, rsp = 0xffffff8810df2cf0, rbp = 0 ---

If there's someone interested in debugging this further, please let me
know what I can do to help.
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"



Index: netinet/tcp_output.c
===================================================================
--- netinet/tcp_output.c        (revision 211958)
+++ netinet/tcp_output.c        (working copy)
@@ -466,9 +466,8 @@
        }
 
        /*
-        * Truncate to the maximum segment length or enable TCP Segmentation
-        * Offloading (if supported by hardware) and ensure that FIN is removed
-        * if the length no longer contains the last data byte.
+        * Decide if we can use TCP Segmentation Offloading (if supported by
+        * hardware).
         *
         * TSO may only be used if we are in a pure bulk sending state.  The
         * presence of TCP-MD5, SACK retransmits, SACK advertizements and
@@ -476,10 +475,6 @@
         * (except for the sequence number) for all generated packets.  This
         * makes it impossible to transmit any options which vary per generated
         * segment or packet.
-        *
-        * The length of TSO bursts is limited to TCP_MAXWIN.  That limit and
-        * removal of FIN (if not already catched here) are handled later after
-        * the exact length of the TCP options are known.
         */
 #ifdef IPSEC
        /*
@@ -488,22 +483,15 @@
         */
        ipsec_optlen = ipsec_hdrsiz_tcp(tp);
 #endif
-       if (len > tp->t_maxseg) {
-               if ((tp->t_flags & TF_TSO) && V_tcp_do_tso &&
-                   ((tp->t_flags & TF_SIGNATURE) == 0) &&
-                   tp->rcv_numsacks == 0 && sack_rxmit == 0 &&
-                   tp->t_inpcb->inp_options == NULL &&
-                   tp->t_inpcb->in6p_options == NULL
+       if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg &&
+           ((tp->t_flags & TF_SIGNATURE) == 0) &&
+           tp->rcv_numsacks == 0 && sack_rxmit == 0 &&
 #ifdef IPSEC
-                   && ipsec_optlen == 0
+           ipsec_optlen == 0 &&
 #endif
-                   ) {
-                       tso = 1;
-               } else {
-                       len = tp->t_maxseg;
-                       sendalot = 1;
-               }
-       }
+           tp->t_inpcb->inp_options == NULL &&
+           tp->t_inpcb->in6p_options == NULL)
+               tso = 1;
 
        if (sack_rxmit) {
                if (SEQ_LT(p->rxmit + len, tp->snd_una + so->so_snd.sb_cc))
@@ -733,28 +747,54 @@
         * bump the packet length beyond the t_maxopd length.
         * Clear the FIN bit because we cut off the tail of
         * the segment.
-        *
-        * When doing TSO limit a burst to TCP_MAXWIN minus the
-        * IP, TCP and Options length to keep ip->ip_len from
-        * overflowing.  Prevent the last segment from being
-        * fractional thus making them all equal sized and set
-        * the flag to continue sending.  TSO is disabled when
-        * IP options or IPSEC are present.
         */
        if (len + optlen + ipoptlen > tp->t_maxopd) {
                flags &= ~TH_FIN;
+
+               /*
+                * TSO is disabled when IP options or IPSEC are present.
+                */
                if (tso) {
-                       if (len > TCP_MAXWIN - hdrlen - optlen) {
-                               len = TCP_MAXWIN - hdrlen - optlen;
-                               len = len - (len % (tp->t_maxopd - optlen));
+                       KASSERT(ipoptlen == 0,
+                           ("%s: TSO can't do IP options", __func__));
+
+                       /*
+                        * When doing TSO limit a burst to IP_MAXPACKET
+                        * IP, TCP and Options length to keep ip->ip_len
+                        * from overflowing.
+                        */
+                       if (len > IP_MAXPACKET - hdrlen) {
+                               len = IP_MAXPACKET - hdrlen;
                                sendalot = 1;
-                       } else if (tp->t_flags & TF_NEEDFIN)
+                       }
+
+                       /*
+                        * Prevent the last segment from being
+                        * fractional unless there is no further
+                        * data and the send sockbuf can be emptied.
+                        */
+                       if (sendalot && off + len < so->so_snd.sb_cc) {
+                               len -= len % (tp->t_maxopd - optlen);
                                sendalot = 1;
+                       }
+
+                       /*
+                        * Send the FIN in a separate segment
+                        * after the bulk sending is done.
+                        * We don't trust the TSO implementations
+                        * to clear the FIN flag on all but the
+                        * last segment.
+                        */
+                       if (tp->t_flags & TF_NEEDFIN)
+                               sendalot = 1;
+
                } else {
                        len = tp->t_maxopd - optlen - ipoptlen;
                        sendalot = 1;
                }
        }
+       KASSERT(len + hdrlen + ipoptlen <= IP_MAXPACKET,
+           ("%s: len too big", __func__));
 
 /*#ifdef DIAGNOSTIC*/
 #ifdef INET6
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to