Hi,

This removes the system wide if_slowtimo timeout and lets every
interface with a valid if_watchdog method register it's own.
The rational is to get rid of the ifnet loop in the softclock
context to avoid further complications with concurrent access
to the ifnet list.  This might also save some cpu cycles in the
runtime if number of interfaces is large while only a fraction
all of them have a watchdog routine.

This has originally come up on NetBSD mailing lists with some
rather complicated locking strategy.  Masao Uebayashi has later
proposed a similar solution.

The diff was looked at and corrected by mpi@.  I've tested the
trunk and a system build as well.  OK?

Index: sys/net/if.c
===================================================================
RCS file: /home/cvs/src/sys/net/if.c,v
retrieving revision 1.303
diff -u -p -r1.303 if.c
--- sys/net/if.c        3 Nov 2014 11:02:08 -0000       1.303
+++ sys/net/if.c        22 Nov 2014 16:25:34 -0000
@@ -135,7 +135,6 @@ void        if_attach_common(struct ifnet *);
 void   if_detach_queues(struct ifnet *, struct ifqueue *);
 void   if_detached_start(struct ifnet *);
 int    if_detached_ioctl(struct ifnet *, u_long, caddr_t);
-void   if_detached_watchdog(struct ifnet *);
 
 int    if_getgroup(caddr_t, struct ifnet *);
 int    if_getgroupmembers(caddr_t);
@@ -171,12 +170,8 @@ int        net_livelocked(void);
 void
 ifinit()
 {
-       static struct timeout if_slowtim;
-
-       timeout_set(&if_slowtim, if_slowtimo, &if_slowtim);
        timeout_set(&net_tick_to, net_tick, &net_tick_to);
 
-       if_slowtimo(&if_slowtim);
        net_tick(&net_tick_to);
 }
 
@@ -272,6 +267,11 @@ if_attachsetup(struct ifnet *ifp)
        pfi_attach_ifnet(ifp);
 #endif
 
+       ifp->if_wdtimo = malloc(sizeof(*ifp->if_wdtimo), M_TEMP,
+           M_WAITOK|M_ZERO);
+       timeout_set(ifp->if_wdtimo, if_slowtimo, ifp);
+       if_slowtimo(ifp);
+
        /* Announce the interface. */
        rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
 }
@@ -483,7 +483,7 @@ if_detach(struct ifnet *ifp)
        ifp->if_flags &= ~IFF_OACTIVE;
        ifp->if_start = if_detached_start;
        ifp->if_ioctl = if_detached_ioctl;
-       ifp->if_watchdog = if_detached_watchdog;
+       ifp->if_watchdog = NULL;
 
        /*
         * Call detach hooks from head to tail.  To make sure detach
@@ -492,6 +492,10 @@ if_detach(struct ifnet *ifp)
         */
        dohooks(ifp->if_detachhooks, HOOK_REMOVE | HOOK_FREE);
 
+       /* Remove the watchdog timeout */
+       timeout_del(ifp->if_wdtimo);
+       free(ifp->if_wdtimo, M_TEMP, sizeof(*ifp->if_wdtimo));
+
 #if NBRIDGE > 0
        /* Remove the interface from any bridge it is part of.  */
        if (ifp->if_bridgeport)
@@ -1162,25 +1166,22 @@ if_link_state_change_task(void *arg, voi
 }
 
 /*
- * Handle interface watchdog timer routines.  Called
- * from softclock, we decrement timers (if set) and
+ * Handle interface watchdog timer routine.  Called
+ * from softclock, we decrement timer (if set) and
  * call the appropriate interface routine on expiration.
  */
 void
 if_slowtimo(void *arg)
 {
-       struct timeout *to = (struct timeout *)arg;
-       struct ifnet *ifp;
+       struct ifnet *ifp = arg;
        int s = splnet();
 
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
-               if (ifp->if_timer == 0 || --ifp->if_timer)
-                       continue;
-               if (ifp->if_watchdog)
+       if (ifp->if_watchdog) {
+               if (ifp->if_timer > 0 && --ifp->if_timer == 0)
                        (*ifp->if_watchdog)(ifp);
+               timeout_add(ifp->if_wdtimo, hz / IFNET_SLOWHZ);
        }
        splx(s);
-       timeout_add(to, hz / IFNET_SLOWHZ);
 }
 
 /*
@@ -1824,12 +1825,6 @@ int
 if_detached_ioctl(struct ifnet *ifp, u_long a, caddr_t b)
 {
        return ENODEV;
-}
-
-void
-if_detached_watchdog(struct ifnet *ifp)
-{
-       /* nothing */
 }
 
 /*
Index: sys/net/if_trunk.c
===================================================================
RCS file: /home/cvs/src/sys/net/if_trunk.c,v
retrieving revision 1.91
diff -u -p -r1.91 if_trunk.c
--- sys/net/if_trunk.c  18 Nov 2014 02:37:31 -0000      1.91
+++ sys/net/if_trunk.c  22 Nov 2014 16:25:34 -0000
@@ -344,11 +344,13 @@ trunk_port_create(struct trunk_softc *tr
        tp->tp_iftype = ifp->if_type;
        ifp->if_type = IFT_IEEE8023ADLAG;
        ifp->if_tp = (caddr_t)tp;
-       tp->tp_watchdog = ifp->if_watchdog;
-       ifp->if_watchdog = trunk_port_watchdog;
        tp->tp_ioctl = ifp->if_ioctl;
        ifp->if_ioctl = trunk_port_ioctl;
 
+       timeout_del(ifp->if_wdtimo);
+       tp->tp_watchdog = ifp->if_watchdog;
+       ifp->if_watchdog = trunk_port_watchdog;
+
        tp->tp_if = ifp;
        tp->tp_trunk = tr;
 
@@ -427,8 +429,8 @@ trunk_port_destroy(struct trunk_port *tp
 
        /* Restore interface */
        ifp->if_type = tp->tp_iftype;
-       ifp->if_watchdog = tp->tp_watchdog;
        ifp->if_ioctl = tp->tp_ioctl;
+       ifp->if_watchdog = tp->tp_watchdog;
        ifp->if_tp = NULL;
 
        hook_disestablish(ifp->if_linkstatehooks, tp->lh_cookie);
@@ -464,6 +466,9 @@ trunk_port_destroy(struct trunk_port *tp
 
        /* Update trunk capabilities */
        tr->tr_capabilities = trunk_capabilities(tr);
+
+       /* Reestablish watchdog timeout */
+       if_slowtimo(ifp);
 
        return (0);
 }
Index: sys/net/if_var.h
===================================================================
RCS file: /home/cvs/src/sys/net/if_var.h,v
retrieving revision 1.12
diff -u -p -r1.12 if_var.h
--- sys/net/if_var.h    8 Jul 2014 04:02:14 -0000       1.12
+++ sys/net/if_var.h    22 Nov 2014 16:25:34 -0000
@@ -72,6 +72,7 @@ struct mbuf;
 struct proc;
 struct rtentry;
 struct socket;
+struct timeout;
 struct ether_header;
 struct arpcom;
 struct rt_addrinfo;
@@ -147,6 +148,7 @@ struct ifnet {                              /* and the 
entries */
        char    if_description[IFDESCRSIZE]; /* interface description */
        u_short if_rtlabelid;           /* next route label */
        u_int8_t if_priority;
+       struct  timeout *if_wdtimo;     /* watchdog timeout */
 
        /* procedure handles */
                                        /* output routine (enqueue) */

Reply via email to