On Sun, Nov 23, 2014 at 12:06 +0100, Martin Pieuchot wrote:
> On 23/11/14(Sun) 02:10, Mike Belopuhov wrote:
> > 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?
> 
> I'm basically ok, some remarks below.
> 
> 
> What about putting the allocation inside if_attach_common() with the
> hooks that are allocated for the same reason?

Sure.

> Maybe we should explain why we allocate them?
> 

We all know why, don't think it will help anything.

New version.  OK?


diff --git sys/net/if.c sys/net/if.c
index 0632eec..679c8c8 100644
--- sys/net/if.c
+++ sys/net/if.c
@@ -133,11 +133,10 @@ void      if_attachdomain1(struct ifnet *);
 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);
 int    if_getgroupattribs(caddr_t);
 int    if_setgroupattribs(caddr_t);
@@ -169,16 +168,12 @@ int       net_livelocked(void);
  * parameters.
  */
 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);
 }
 
 static unsigned int if_index = 0;
 static unsigned int if_indexlim = 0;
@@ -270,10 +265,13 @@ if_attachsetup(struct ifnet *ifp)
                if_attachdomain1(ifp);
 #if NPF > 0
        pfi_attach_ifnet(ifp);
 #endif
 
+       timeout_set(ifp->if_slowtimo, if_slowtimo, ifp);
+       if_slowtimo(ifp);
+
        /* Announce the interface. */
        rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
 }
 
 /*
@@ -426,10 +424,13 @@ if_attach_common(struct ifnet *ifp)
            M_TEMP, M_WAITOK);
        TAILQ_INIT(ifp->if_linkstatehooks);
        ifp->if_detachhooks = malloc(sizeof(*ifp->if_detachhooks),
            M_TEMP, M_WAITOK);
        TAILQ_INIT(ifp->if_detachhooks);
+
+       ifp->if_slowtimo = malloc(sizeof(*ifp->if_slowtimo), M_TEMP,
+           M_WAITOK|M_ZERO);
 }
 
 void
 if_start(struct ifnet *ifp)
 {
@@ -481,19 +482,22 @@ if_detach(struct ifnet *ifp)
        struct domain *dp;
 
        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
         * hooks are executed in the reverse order they were added, all
         * the hooks have to be added to the head!
         */
        dohooks(ifp->if_detachhooks, HOOK_REMOVE | HOOK_FREE);
 
+       /* Remove the watchdog timeout */
+       timeout_del(ifp->if_slowtimo);
+
 #if NBRIDGE > 0
        /* Remove the interface from any bridge it is part of.  */
        if (ifp->if_bridgeport)
                bridge_ifdetach(ifp);
 #endif
@@ -577,10 +581,12 @@ do { \
 
        free(ifp->if_addrhooks, M_TEMP, 0);
        free(ifp->if_linkstatehooks, M_TEMP, 0);
        free(ifp->if_detachhooks, M_TEMP, 0);
 
+       free(ifp->if_slowtimo, M_TEMP, sizeof(*ifp->if_slowtimo));
+
        for (dp = domains; dp; dp = dp->dom_next) {
                if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
                        (*dp->dom_ifdetach)(ifp,
                            ifp->if_afdata[dp->dom_family]);
        }
@@ -1160,29 +1166,26 @@ if_link_state_change_task(void *arg, void *unused)
        }
        splx(s);
 }
 
 /*
- * 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_slowtimo, hz / IFNET_SLOWHZ);
        }
        splx(s);
-       timeout_add(to, hz / IFNET_SLOWHZ);
 }
 
 /*
  * Map interface name to interface structure pointer.
  */
@@ -1824,16 +1827,10 @@ int
 if_detached_ioctl(struct ifnet *ifp, u_long a, caddr_t b)
 {
        return ENODEV;
 }
 
-void
-if_detached_watchdog(struct ifnet *ifp)
-{
-       /* nothing */
-}
-
 /*
  * Create interface group without members
  */
 struct ifg_group *
 if_creategroup(const char *groupname)
diff --git sys/net/if_trunk.c sys/net/if_trunk.c
index 90e7fe9..c4bc760 100644
--- sys/net/if_trunk.c
+++ sys/net/if_trunk.c
@@ -342,15 +342,17 @@ trunk_port_create(struct trunk_softc *tr, struct ifnet 
*ifp)
 
        /* Change the interface type */
        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_slowtimo);
+       tp->tp_watchdog = ifp->if_watchdog;
+       ifp->if_watchdog = trunk_port_watchdog;
+
        tp->tp_if = ifp;
        tp->tp_trunk = tr;
 
        /* Save port link layer address */
        bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN);
@@ -463,10 +465,13 @@ trunk_port_destroy(struct trunk_port *tp)
        free(tp, M_DEVBUF, 0);
 
        /* Update trunk capabilities */
        tr->tr_capabilities = trunk_capabilities(tr);
 
+       /* Reestablish watchdog timeout */
+       if_slowtimo(ifp);
+
        return (0);
 }
 
 void
 trunk_port_watchdog(struct ifnet *ifp)
diff --git sys/net/if_var.h sys/net/if_var.h
index cd40d8b..19f4f56 100644
--- sys/net/if_var.h
+++ sys/net/if_var.h
@@ -70,10 +70,11 @@
 
 struct mbuf;
 struct proc;
 struct rtentry;
 struct socket;
+struct timeout;
 struct ether_header;
 struct arpcom;
 struct rt_addrinfo;
 struct ifnet;
 struct hfsc_if;
@@ -145,10 +146,11 @@ struct ifnet {                            /* and the 
entries */
        u_int32_t if_hardmtu;           /* maximum MTU device supports */
        u_int   if_rdomain;             /* routing instance */
        char    if_description[IFDESCRSIZE]; /* interface description */
        u_short if_rtlabelid;           /* next route label */
        u_int8_t if_priority;
+       struct  timeout *if_slowtimo;   /* watchdog timeout */
 
        /* procedure handles */
                                        /* output routine (enqueue) */
        int     (*if_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
                     struct rtentry *);

Reply via email to