- Add rtfree_remote(), which send rtentry to its owner CPU to be freed.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 11 Sep 2008 11:23:29 +0000 (11:23 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 11 Sep 2008 11:23:29 +0000 (11:23 +0000)
  Print backtrace, if net.route.remote_free_panic is 0.  This function
  only serves as _temporary_ workaround.
- In ip_output(), if passed rtentry cache's owner CPU is not the current,
  then keep it untouched and use the stack variable to relocate the route.
  Add comment about it.  This at least could happen in the following
  callgraph on a TCP socket, on which listen(2) has been called:
  ip_input() -> tcp_input() -> tcp_respond() -> ip_output()

Related to Dragonfly-bug: <http://bugs.dragonflybsd.org/issue1134>

sys/net/route.c
sys/net/route.h
sys/netinet/in_pcb.c
sys/netinet/ip_output.c

index f5f2c9f..b114dd9 100644 (file)
@@ -64,7 +64,7 @@
  *
  *     @(#)route.c     8.3 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/net/route.c,v 1.59.2.10 2003/01/17 08:04:00 ru Exp $
- * $DragonFly: src/sys/net/route.c,v 1.36 2008/07/20 18:43:12 nant Exp $
+ * $DragonFly: src/sys/net/route.c,v 1.37 2008/09/11 11:23:29 sephe Exp $
  */
 
 #include "opt_inet.h"
@@ -128,6 +128,11 @@ SYSCTL_INT(_net_route, OID_AUTO, route_debug, CTLFLAG_RW,
            &route_debug, 0, "");
 #endif
 
+static int remote_free_panic = 0;
+SYSCTL_INT(_net_route, OID_AUTO, remote_free_panic, CTLFLAG_RW,
+           &remote_free_panic, 0, "");
+extern void    db_print_backtrace(void);
+
 /*
  * Initialize the route table(s) for protocol domains and
  * create a helper thread which will be responsible for updating
@@ -313,6 +318,16 @@ unreach:
 void
 rtfree(struct rtentry *rt)
 {
+       if (rt->rt_cpuid == mycpuid)
+               rtfree_oncpu(rt);
+       else
+               rtfree_remote(rt, 1);
+}
+
+void
+rtfree_oncpu(struct rtentry *rt)
+{
+       KKASSERT(rt->rt_cpuid == mycpuid);
        KASSERT(rt->rt_refcnt > 0, ("rtfree: rt_refcnt %ld", rt->rt_refcnt));
 
        --rt->rt_refcnt;
@@ -334,6 +349,40 @@ rtfree(struct rtentry *rt)
        }
 }
 
+static void
+rtfree_remote_dispatch(struct netmsg *nmsg)
+{
+       struct lwkt_msg *lmsg = &nmsg->nm_lmsg;
+       struct rtentry *rt = lmsg->u.ms_resultp;
+
+       rtfree_oncpu(rt);
+       lwkt_replymsg(lmsg, 0);
+}
+
+void
+rtfree_remote(struct rtentry *rt, int allow_panic)
+{
+       struct netmsg nmsg;
+       struct lwkt_msg *lmsg;
+
+       KKASSERT(rt->rt_cpuid != mycpuid);
+
+       if (remote_free_panic && allow_panic) {
+               panic("rt remote free rt_cpuid %d, mycpuid %d\n",
+                     rt->rt_cpuid, mycpuid);
+       } else {
+               kprintf("rt remote free rt_cpuid %d, mycpuid %d\n",
+                       rt->rt_cpuid, mycpuid);
+               db_print_backtrace();
+       }
+
+       netmsg_init(&nmsg, &curthread->td_msgport, 0, rtfree_remote_dispatch);
+       lmsg = &nmsg.nm_lmsg;
+       lmsg->u.ms_resultp = rt;
+
+       lwkt_domsg(rtable_portfn(rt->rt_cpuid), lmsg, 0);
+}
+
 static int
 rtredirect_oncpu(struct sockaddr *dst, struct sockaddr *gateway,
                 struct sockaddr *netmask, int flags, struct sockaddr *src)
index 70d91f1..773c1b9 100644 (file)
@@ -64,7 +64,7 @@
  *
  *     @(#)route.h     8.4 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/net/route.h,v 1.36.2.5 2002/02/01 11:48:01 ru Exp $
- * $DragonFly: src/sys/net/route.h,v 1.23 2008/07/07 22:02:10 nant Exp $
+ * $DragonFly: src/sys/net/route.h,v 1.24 2008/09/11 11:23:29 sephe Exp $
  */
 
 #ifndef _NET_ROUTE_H_
@@ -389,17 +389,27 @@ int        rtrequest_global (int, struct sockaddr *,
 int     rtrequest1 (int, struct rt_addrinfo *, struct rtentry **);
 int     rtrequest1_global (int, struct rt_addrinfo *, rtrequest1_callback_func_t, void *);
 
+void   rtfree_oncpu(struct rtentry *);
+void   rtfree_remote(struct rtentry *, int);
 void   rt_print(struct rt_addrinfo *, struct rtentry *);
 void   rt_addrinfo_print(int cmd, struct rt_addrinfo *);
 void   sockaddr_print(struct sockaddr *);
 
+#ifndef _SYS_GLOBALDATA_H_
+#include <sys/globaldata.h>
+#endif
+
 static __inline void
 RTFREE(struct rtentry *rt)
 {
-       if (rt->rt_refcnt <= 1)
-               rtfree(rt);
-       else
-               --rt->rt_refcnt;
+       if (rt->rt_cpuid == mycpuid) {
+               if (rt->rt_refcnt <= 1)
+                       rtfree_oncpu(rt);
+               else
+                       --rt->rt_refcnt;
+       } else {
+               rtfree_remote(rt, 1);
+       }
 }
 
 static __inline
index a69b9c1..5868b6f 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
  * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.59.2.27 2004/01/02 04:06:42 ambrisko Exp $
- * $DragonFly: src/sys/netinet/in_pcb.c,v 1.46 2008/06/08 08:38:05 sephe Exp $
+ * $DragonFly: src/sys/netinet/in_pcb.c,v 1.47 2008/09/11 11:23:29 sephe Exp $
  */
 
 #include "opt_ipsec.h"
@@ -658,8 +658,20 @@ in_pcbdetach(struct inpcb *inp)
        sofree(so);
        if (inp->inp_options)
                m_free(inp->inp_options);
-       if (inp->inp_route.ro_rt)
-               rtfree(inp->inp_route.ro_rt);
+       if (inp->inp_route.ro_rt) {
+               /*
+                * XXX DIRTY WORKAROUND
+                * It is known that closing TCP listen socket _may_
+                * free cached rtentry on the CPU, which is _not_
+                * the owner of the rtentry.  Before we work out a
+                * proper solution, just disallow panic and prints
+                * backtrace (in rtfree_remote())
+                */
+               if (inp->inp_route.ro_rt->rt_cpuid == mycpuid)
+                       rtfree(inp->inp_route.ro_rt);
+               else
+                       rtfree_remote(inp->inp_route.ro_rt, 0 /* no panic */);
+       }
        ip_freemoptions(inp->inp_moptions);
        inp->inp_vflag = 0;
        zfree(ipi->ipi_zone, inp);
index 2fda413..70ad668 100644 (file)
@@ -28,7 +28,7 @@
  *
  *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/netinet/ip_output.c,v 1.99.2.37 2003/04/15 06:44:45 silby Exp $
- * $DragonFly: src/sys/netinet/ip_output.c,v 1.58 2008/09/08 12:41:39 sephe Exp $
+ * $DragonFly: src/sys/netinet/ip_output.c,v 1.59 2008/09/11 11:23:29 sephe Exp $
  */
 
 #define _IP_VHL
@@ -237,6 +237,15 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
        if (ro == NULL) {
                ro = &iproute;
                bzero(ro, sizeof *ro);
+       } else if (ro->ro_rt != NULL && ro->ro_rt->rt_cpuid != mycpuid) {
+               /*
+                * XXX
+                * If the cached rtentry's owner CPU is not the current CPU,
+                * then don't touch the cached rtentry (remote free is too
+                * expensive in this context); just relocate the route.
+                */
+               ro = &iproute;
+               bzero(ro, sizeof *ro);
        }
 
        if (m->m_pkthdr.fw_flags & IPFORWARD_MBUF_TAGGED) {
@@ -263,6 +272,7 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
 
                KKASSERT(ro == &iproute);
                *ro = dn_pkt->ro; /* structure copy */
+               KKASSERT(ro->ro_rt == NULL || ro->ro_rt->rt_cpuid == mycpuid);
 
                dst = dn_pkt->dn_dst;
                if (dst == (struct sockaddr_in *)&(dn_pkt->ro.ro_dst)) {