Source-Changes-HG archive

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

[src/netbsd-7]: src/sys Pull up following revision(s) (requested by skrll/oza...



details:   https://anonhg.NetBSD.org/src/rev/897374dc57b3
branches:  netbsd-7
changeset: 800208:897374dc57b3
user:      snj <snj%NetBSD.org@localhost>
date:      Fri May 12 05:44:10 2017 +0000

description:
Pull up following revision(s) (requested by skrll/ozaki-r in ticket #1402):
        sys/net/route.c: revision 1.170 via patch
        sys/netinet/ip_flow.c: revision 1.73 via patch
        sys/netinet6/ip6_flow.c: revision 1.28 via patch
        sys/netinet6/nd6.c: revision 1.203 via patch
Run timers in workqueue
Timers (such as nd6_timer) typically free/destroy some data in callout
(softint). If we apply psz/psref for such data, we cannot do free/destroy
process in there because synchronization of psz/psref cannot be used in
softint. So run timer callbacks in workqueue works (normal LWP context).
Doing workqueue_enqueue a work twice (i.e., call workqueue_enqueue before
a previous task is scheduled) isn't allowed. For nd6_timer and
rt_timer_timer, this doesn't happen because callout_reset is called only
from workqueue's work. OTOH, ip{,6}flow_slowtimo's callout can be called
before its work starts and completes because the callout is periodically
called regardless of completion of the work. To avoid such a situation,
add a flag for each protocol; the flag is set true when a work is
enqueued and set false after the work finished. workqueue_enqueue is
called only if the flag is false.
Proposed on tech-net and tech-kern.

diffstat:

 sys/net/route.c         |  27 ++++++++++++++++++++++-----
 sys/netinet/ip_flow.c   |  38 ++++++++++++++++++++++++++++++++++----
 sys/netinet6/ip6_flow.c |  36 +++++++++++++++++++++++++++++++++---
 sys/netinet6/nd6.c      |  23 ++++++++++++++++++++---
 4 files changed, 109 insertions(+), 15 deletions(-)

diffs (truncated from 351 to 300 lines):

diff -r bf7ac1ab5a30 -r 897374dc57b3 sys/net/route.c
--- a/sys/net/route.c   Fri May 12 05:33:37 2017 +0000
+++ b/sys/net/route.c   Fri May 12 05:44:10 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: route.c,v 1.132 2014/06/06 01:27:32 rmind Exp $        */
+/*     $NetBSD: route.c,v 1.132.2.1 2017/05/12 05:44:10 snj Exp $      */
 
 /*-
  * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -93,7 +93,7 @@
 #include "opt_route.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.132 2014/06/06 01:27:32 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.132.2.1 2017/05/12 05:44:10 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/kmem.h>
@@ -110,6 +110,7 @@
 #include <sys/ioctl.h>
 #include <sys/pool.h>
 #include <sys/kauth.h>
+#include <sys/workqueue.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -133,6 +134,8 @@
 struct pool rttimer_pool;
 
 struct callout rt_timer_ch; /* callout for rt_timer_timer() */
+struct workqueue       *rt_timer_wq;
+struct work            rt_timer_wk;
 
 #ifdef RTFLUSH_DEBUG
 static int _rtcache_debug = 0;
@@ -1031,14 +1034,22 @@
  * that this is run when the first queue is added...
  */
 
+static void rt_timer_work(struct work *, void *);
+
 void
 rt_timer_init(void)
 {
+       int error;
+
        assert(rt_init_done == 0);
 
        LIST_INIT(&rttimer_queue_head);
        callout_init(&rt_timer_ch, 0);
        callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
+       error = workqueue_create(&rt_timer_wq, "rt_timer",
+           rt_timer_work, NULL, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE);
+       if (error)
+               panic("%s: workqueue_create failed (%d)\n", __func__, error);
        rt_init_done = 1;
 }
 
@@ -1171,9 +1182,8 @@
        return 0;
 }
 
-/* ARGSUSED */
-void
-rt_timer_timer(void *arg)
+static void
+rt_timer_work(struct work *wk, void *arg)
 {
        struct rttimer_queue *rtq;
        struct rttimer *r;
@@ -1198,6 +1208,13 @@
        callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
 }
 
+void
+rt_timer_timer(void *arg)
+{
+
+       workqueue_enqueue(rt_timer_wq, &rt_timer_wk, NULL);
+}
+
 static struct rtentry *
 _rtcache_init(struct route *ro, int flag)
 {
diff -r bf7ac1ab5a30 -r 897374dc57b3 sys/netinet/ip_flow.c
--- a/sys/netinet/ip_flow.c     Fri May 12 05:33:37 2017 +0000
+++ b/sys/netinet/ip_flow.c     Fri May 12 05:44:10 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_flow.c,v 1.64 2014/05/22 22:01:12 rmind Exp $       */
+/*     $NetBSD: ip_flow.c,v 1.64.2.1 2017/05/12 05:44:10 snj Exp $     */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.64 2014/05/22 22:01:12 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.64.2.1 2017/05/12 05:44:10 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -45,6 +45,7 @@
 #include <sys/kernel.h>
 #include <sys/pool.h>
 #include <sys/sysctl.h>
+#include <sys/workqueue.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -96,6 +97,10 @@
 
 static void ipflow_sysctl_init(struct sysctllog **);
 
+static void ipflow_slowtimo_work(struct work *, void *);
+static struct workqueue        *ipflow_slowtimo_wq;
+static struct work     ipflow_slowtimo_wk;
+
 static size_t 
 ipflow_hash(const struct ip *ip)
 {
@@ -130,6 +135,12 @@
 void
 ipflow_poolinit(void)
 {
+       int error;
+
+       error = workqueue_create(&ipflow_slowtimo_wq, "ipflow_slowtimo",
+           ipflow_slowtimo_work, NULL, PRI_SOFTNET, IPL_NET, WQ_MPSAFE);
+       if (error != 0)
+               panic("%s: workqueue_create failed (%d)\n", __func__, error);
 
        pool_init(&ipflow_pool, sizeof(struct ipflow), 0, 0, 0, "ipflowpl",
            NULL, IPL_NET);
@@ -390,8 +401,10 @@
        return NULL;
 }
 
-void
-ipflow_slowtimo(void)
+static bool ipflow_work_enqueued = false;
+
+static void
+ipflow_slowtimo_work(struct work *wk, void *arg)
 {
        struct rtentry *rt;
        struct ipflow *ipf, *next_ipf;
@@ -415,11 +428,28 @@
                        ipf->ipf_uses = 0;
                }
        }
+       ipflow_work_enqueued = false;
        KERNEL_UNLOCK_ONE(NULL);
        mutex_exit(softnet_lock);
 }
 
 void
+ipflow_slowtimo(void)
+{
+
+       /* Avoid enqueuing another work when one is already enqueued */
+       KERNEL_LOCK(1, NULL);
+       if (ipflow_work_enqueued) {
+               KERNEL_UNLOCK_ONE(NULL);
+               return;
+       }
+       ipflow_work_enqueued = true;
+       KERNEL_UNLOCK_ONE(NULL);
+
+       workqueue_enqueue(ipflow_slowtimo_wq, &ipflow_slowtimo_wk, NULL);
+}
+
+void
 ipflow_create(const struct route *ro, struct mbuf *m)
 {
        const struct ip *const ip = mtod(m, const struct ip *);
diff -r bf7ac1ab5a30 -r 897374dc57b3 sys/netinet6/ip6_flow.c
--- a/sys/netinet6/ip6_flow.c   Fri May 12 05:33:37 2017 +0000
+++ b/sys/netinet6/ip6_flow.c   Fri May 12 05:44:10 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip6_flow.c,v 1.23 2014/05/20 20:23:56 bouyer Exp $     */
+/*     $NetBSD: ip6_flow.c,v 1.23.2.1 2017/05/12 05:44:10 snj Exp $    */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_flow.c,v 1.23 2014/05/20 20:23:56 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_flow.c,v 1.23.2.1 2017/05/12 05:44:10 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -52,6 +52,7 @@
 #include <sys/kernel.h>
 #include <sys/pool.h>
 #include <sys/sysctl.h>
+#include <sys/workqueue.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -92,6 +93,10 @@
 static struct ip6flowhead ip6flowlist;
 static int ip6flow_inuse;
 
+static void ip6flow_slowtimo_work(struct work *, void *);
+static struct workqueue        *ip6flow_slowtimo_wq;
+static struct work     ip6flow_slowtimo_wk;
+
 /*
  * Insert an ip6flow into the list.
  */
@@ -182,6 +187,12 @@
 {
        struct ip6flowhead *new_table;
        size_t i;
+       int error;
+
+       error = workqueue_create(&ip6flow_slowtimo_wq, "ip6flow_slowtimo",
+           ip6flow_slowtimo_work, NULL, PRI_SOFTNET, IPL_NET, WQ_MPSAFE);
+       if (error != 0)
+               panic("%s: workqueue_create failed (%d)\n", __func__, error);
 
        new_table = (struct ip6flowhead *)malloc(sizeof(struct ip6flowhead) *
            table_size, M_RTABLE, M_NOWAIT);
@@ -415,8 +426,10 @@
        return NULL;
 }
 
+static bool ip6flow_work_enqueued = false;
+
 void
-ip6flow_slowtimo(void)
+ip6flow_slowtimo_work(struct work *wk, void *arg)
 {
        struct ip6flow *ip6f, *next_ip6f;
 
@@ -436,11 +449,28 @@
                        ip6f->ip6f_forwarded = 0;
                }
        }
+       ip6flow_work_enqueued = false;
 
        KERNEL_UNLOCK_ONE(NULL);
        mutex_exit(softnet_lock);
 }
 
+void
+ip6flow_slowtimo(void)
+{
+
+       /* Avoid enqueuing another work when one is already enqueued */
+       KERNEL_LOCK(1, NULL);
+       if (ip6flow_work_enqueued) {
+               KERNEL_UNLOCK_ONE(NULL);
+               return;
+       }
+       ip6flow_work_enqueued = true;
+       KERNEL_UNLOCK_ONE(NULL);
+
+       workqueue_enqueue(ip6flow_slowtimo_wq, &ip6flow_slowtimo_wk, NULL);
+}
+
 /*
  * We have successfully forwarded a packet using the normal
  * IPv6 stack. Now create/update a flow.
diff -r bf7ac1ab5a30 -r 897374dc57b3 sys/netinet6/nd6.c
--- a/sys/netinet6/nd6.c        Fri May 12 05:33:37 2017 +0000
+++ b/sys/netinet6/nd6.c        Fri May 12 05:44:10 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nd6.c,v 1.152.2.3 2015/04/06 01:32:33 snj Exp $        */
+/*     $NetBSD: nd6.c,v 1.152.2.4 2017/05/12 05:44:10 snj Exp $        */
 /*     $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $   */
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152.2.3 2015/04/06 01:32:33 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.152.2.4 2017/05/12 05:44:10 snj Exp $");
 
 #include "bridge.h"
 #include "carp.h"
@@ -53,6 +53,7 @@
 #include <sys/syslog.h>
 #include <sys/queue.h>
 #include <sys/cprng.h>
+#include <sys/workqueue.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -122,11 +123,14 @@
 static void nd6_slowtimo(void *);
 static int regen_tmpaddr(struct in6_ifaddr *);
 static struct llinfo_nd6 *nd6_free(struct rtentry *, int);
+static void nd6_timer_work(struct work *, void *);
 static void nd6_llinfo_timer(void *);
 static void clear_llinfo_pqueue(struct llinfo_nd6 *);



Home | Main Index | Thread Index | Old Index