NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/39940 (agr locking error)



On Wed, Jun 10, 2009 at 05:06:58PM +0000, dyoung%NetBSD.org@localhost wrote:
> Synopsis: agr locking error
> 
> Responsible-Changed-From-To: kern-bug-people->dyoung
> Responsible-Changed-By: dyoung%NetBSD.org@localhost
> Responsible-Changed-When: Wed, 10 Jun 2009 17:06:55 +0000
> Responsible-Changed-Why:
> Looks like I broke it.  Let me see if I can fix it.

Please give this patch a try.

Dave

-- 
David Young             OJC Technologies
dyoung%ojctech.com@localhost      Urbana, IL * (217) 278-3933
Index: in6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6.c,v
retrieving revision 1.151
diff -p -u -u -p -r1.151 in6.c
--- in6.c       12 May 2009 23:01:26 -0000      1.151
+++ in6.c       4 Aug 2009 22:02:13 -0000
@@ -76,6 +76,7 @@ __KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.15
 #include <sys/socketvar.h>
 #include <sys/sockio.h>
 #include <sys/systm.h>
+#include <sys/once.h>
 #include <sys/proc.h>
 #include <sys/time.h>
 #include <sys/kernel.h>
@@ -2230,8 +2231,11 @@ in6_if2idlen(struct ifnet *ifp)
 void *
 in6_domifattach(struct ifnet *ifp)
 {
+       static ONCE_DECL(ifwqest);
        struct in6_ifextra *ext;
 
+       RUN_ONCE(&ifwqest, in6_ifaddrs_wq_establish);
+
        ext = malloc(sizeof(*ext), M_IFADDR, M_WAITOK|M_ZERO);
 
        ext->in6_ifstat = malloc(sizeof(struct in6_ifstat),
Index: in6_ifattach.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_ifattach.c,v
retrieving revision 1.82
diff -p -u -u -p -r1.82 in6_ifattach.c
--- in6_ifattach.c      30 Jul 2009 17:28:36 -0000      1.82
+++ in6_ifattach.c      4 Aug 2009 22:02:13 -0000
@@ -35,6 +35,7 @@ __KERNEL_RCSID(0, "$NetBSD: in6_ifattach
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/kmem.h>
 #include <sys/malloc.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
@@ -42,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: in6_ifattach
 #include <sys/syslog.h>
 #include <sys/md5.h>
 #include <sys/socketvar.h>
+#include <sys/workqueue.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -60,12 +62,27 @@ __KERNEL_RCSID(0, "$NetBSD: in6_ifattach
 
 #include <net/net_osdep.h>
 
+struct in6_ifaddr_work {
+       struct work     iw_work;
+       struct ifindexgen {
+               int     ig_idx;
+               int     ig_gen;
+       }               iw_idxgen,
+                       iw_alt_idxgen;
+       bool            iw_alt_present;
+};
+
 unsigned long in6_maxmtu = 0;
 
 int ip6_auto_linklocal = 1;    /* enable by default */
 
 callout_t in6_tmpaddrtimer_ch;
 
+static struct workqueue *in6_ifaddrs_wq = NULL;
+
+static void in6_ifaddrs_schedule(struct ifnet *, struct ifnet *);
+static void in6_ifaddrs_init(struct ifnet *, struct ifnet *);
+static void in6_ifaddrs_worker(struct work *, void *);
 
 #if 0
 static int get_hostid_ifid(struct ifnet *, struct in6_addr *);
@@ -751,8 +768,6 @@ in6_nigroup(struct ifnet *ifp, const cha
 void
 in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
 {
-       struct in6_ifaddr *ia;
-       struct in6_addr in6;
 
        /* some of the interfaces are inherently not IPv6 capable */
        switch (ifp->if_type) {
@@ -811,6 +826,15 @@ in6_ifattach(struct ifnet *ifp, struct i
                return;
        }
 
+       in6_ifaddrs_schedule(ifp, altifp);
+}
+
+void
+in6_ifaddrs_init(struct ifnet *ifp, struct ifnet *altifp)
+{
+       struct in6_addr in6;
+       struct in6_ifaddr *ia;
+
        /*
         * assign loopback address for loopback interface.
         * XXX multiple loopback interface case.
@@ -835,6 +859,80 @@ in6_ifattach(struct ifnet *ifp, struct i
        }
 }
 
+static struct ifnet *
+getifp(struct ifindexgen *ig)
+{
+       int ifindex = ig->ig_idx;
+       uint64_t ifindex_gen = ig->ig_gen;
+       struct ifnet *ifp;
+
+       if (ifindex2ifnet == NULL)
+               printf("%s: no ifindices in use\n", __func__);
+       else if (ifindex >= if_indexlim) {
+               printf("%s: ifindex %d >= limit %d\n", __func__, ifindex,
+                   if_indexlim);
+       } else if ((ifp = ifindex2ifnet[ifindex]) == NULL)
+               printf("%s: ifindex %d not in use\n", __func__, ifindex);
+       else if (ifp->if_index_gen != ifindex_gen)
+               printf("%s: ifindex %d recycled\n", __func__, ifindex);
+       else
+               return ifp;
+       return NULL;
+}
+
+static void
+in6_ifaddrs_worker(struct work *wk, void *arg)
+{
+       struct in6_ifaddr_work *iw = (struct in6_ifaddr_work *)wk;
+       struct ifnet *altifp = NULL, *ifp;
+
+       if ((ifp = getifp(&iw->iw_idxgen)) != NULL &&
+           (!iw->iw_alt_present ||
+            (altifp = getifp(&iw->iw_alt_idxgen)) != NULL))
+               in6_ifaddrs_init(ifp, altifp);
+
+       kmem_free(iw, sizeof(*iw));
+}
+
+int
+in6_ifaddrs_wq_establish(void)
+{
+       int rc;
+
+       rc = workqueue_create(&in6_ifaddrs_wq, "in6ifaddr", in6_ifaddrs_worker,
+           NULL, PRI_KERNEL, IPL_NET, 0);
+
+       if (rc != 0) {
+               printf("%s: could not create inet6 ifaddrs workqueue.\n",
+                   __func__);
+       }
+       return rc;
+}
+
+void
+in6_ifaddrs_schedule(struct ifnet *ifp, struct ifnet *altifp)
+{
+       struct in6_ifaddr_work *iw;
+       struct ifindexgen *ig, *alt_ig;
+
+       iw = kmem_zalloc(sizeof(*iw), KM_SLEEP);
+
+       ig = &iw->iw_idxgen;
+       alt_ig = &iw->iw_alt_idxgen;
+
+       KASSERT(ifp->if_index < if_indexlim);
+       ig->ig_idx = ifp->if_index;
+       ig->ig_gen = ifp->if_index_gen;
+       if (altifp != NULL) {
+               KASSERT(altifp->if_index < if_indexlim);
+               alt_ig->ig_idx = altifp->if_index;
+               alt_ig->ig_gen = altifp->if_index_gen;
+               iw->iw_alt_present = true;
+       }
+
+       workqueue_enqueue(in6_ifaddrs_wq, &iw->iw_work, NULL);
+}
+
 /*
  * NOTE: in6_ifdetach() does not support loopback if at this moment.
  * We don't need this function in bsdi, because interfaces are never removed
Index: in6_ifattach.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_ifattach.h,v
retrieving revision 1.11
diff -p -u -u -p -r1.11 in6_ifattach.h
--- in6_ifattach.h      1 Nov 2007 20:33:57 -0000       1.11
+++ in6_ifattach.h      4 Aug 2009 22:02:13 -0000
@@ -40,6 +40,7 @@ int in6_get_tmpifid(struct ifnet *, u_in
 void in6_tmpaddrtimer(void *);
 int in6_get_hw_ifid(struct ifnet *, struct in6_addr *);
 int in6_nigroup(struct ifnet *, const char *, int, struct sockaddr_in6 *);
+int in6_ifaddrs_wq_establish(void);
 #endif /* _KERNEL */
 
 #endif /* !_NETINET6_IN6_IFATTACH_H_ */


Home | Main Index | Thread Index | Old Index