Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/net ifnet(9): Defer if_watchdog (a.k.a. if_slowtimo) to ...
details: https://anonhg.NetBSD.org/src/rev/ec9e647db392
branches: trunk
changeset: 369484:ec9e647db392
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sat Aug 20 11:09:24 2022 +0000
description:
ifnet(9): Defer if_watchdog (a.k.a. if_slowtimo) to workqueue.
This is necessary to make mii_down and the *_init/stop routines that
call it to sleep waiting for MII callouts on other CPUs.
Mark the workqueue and callout MP-safe; only take the kernel lock
around the callback.
No kernel bump despite change to struct ifnet because the change is
ABI-compatible and using the callout outside net/if.c has never been
kosher.
diffstat:
sys/net/if.c | 107 +++++++++++++++++++++++++++++++++++++++++++---------------
sys/net/if.h | 4 +-
2 files changed, 80 insertions(+), 31 deletions(-)
diffs (190 lines):
diff -r 270d67592e08 -r ec9e647db392 sys/net/if.c
--- a/sys/net/if.c Sat Aug 20 10:55:27 2022 +0000
+++ b/sys/net/if.c Sat Aug 20 11:09:24 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if.c,v 1.512 2022/08/17 19:56:28 rillig Exp $ */
+/* $NetBSD: if.c,v 1.513 2022/08/20 11:09:24 riastradh Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.512 2022/08/17 19:56:28 rillig Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.513 2022/08/20 11:09:24 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -197,6 +197,8 @@
static pserialize_t ifnet_psz;
static struct workqueue *ifnet_link_state_wq __read_mostly;
+static struct workqueue *if_slowtimo_wq __read_mostly;
+
static kmutex_t if_clone_mtx;
struct ifnet *lo0ifp;
@@ -221,7 +223,8 @@
static void if_detach_queues(struct ifnet *, struct ifqueue *);
static void sysctl_sndq_setup(struct sysctllog **, const char *,
struct ifaltq *);
-static void if_slowtimo(void *);
+static void if_slowtimo_intr(void *);
+static void if_slowtimo_work(struct work *, void *);
static void if_attachdomain1(struct ifnet *);
static int ifconf(u_long, void *);
static int if_transmit(struct ifnet *, struct mbuf *);
@@ -255,6 +258,15 @@
static void if_deferred_start_common(struct ifnet *);
static void if_deferred_start_destroy(struct ifnet *);
+struct if_slowtimo_data {
+ kmutex_t isd_lock;
+ struct callout isd_ch;
+ struct work isd_work;
+ struct ifnet *isd_ifp;
+ bool isd_queued;
+ bool isd_dying;
+};
+
#if defined(INET) || defined(INET6)
static void sysctl_net_pktq_setup(struct sysctllog **, int);
#endif
@@ -333,6 +345,10 @@
KASSERT(error == 0);
PSLIST_INIT(&ifnet_pslist);
+ error = workqueue_create(&if_slowtimo_wq, "ifwdog",
+ if_slowtimo_work, NULL, PRI_SOFTNET, IPL_SOFTCLOCK, WQ_MPSAFE);
+ KASSERTMSG(error == 0, "error=%d", error);
+
if_indexlim = 8;
if_pfil = pfil_head_create(PFIL_TYPE_IFNET, NULL);
@@ -779,11 +795,17 @@
rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
if (ifp->if_slowtimo != NULL) {
- ifp->if_slowtimo_ch =
- kmem_zalloc(sizeof(*ifp->if_slowtimo_ch), KM_SLEEP);
- callout_init(ifp->if_slowtimo_ch, 0);
- callout_setfunc(ifp->if_slowtimo_ch, if_slowtimo, ifp);
- if_slowtimo(ifp);
+ struct if_slowtimo_data *isd;
+
+ isd = kmem_zalloc(sizeof(*isd), KM_SLEEP);
+ mutex_init(&isd->isd_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
+ callout_init(&isd->isd_ch, CALLOUT_MPSAFE);
+ callout_setfunc(&isd->isd_ch, if_slowtimo_intr, ifp);
+ isd->isd_ifp = ifp;
+
+ ifp->if_slowtimo_data = isd;
+
+ if_slowtimo_intr(ifp);
}
if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit)
@@ -1350,11 +1372,20 @@
pserialize_perform(ifnet_psz);
IFNET_GLOBAL_UNLOCK();
- if (ifp->if_slowtimo != NULL && ifp->if_slowtimo_ch != NULL) {
- ifp->if_slowtimo = NULL;
- callout_halt(ifp->if_slowtimo_ch, NULL);
- callout_destroy(ifp->if_slowtimo_ch);
- kmem_free(ifp->if_slowtimo_ch, sizeof(*ifp->if_slowtimo_ch));
+ if (ifp->if_slowtimo != NULL) {
+ struct if_slowtimo_data *isd = ifp->if_slowtimo_data;
+
+ mutex_enter(&isd->isd_lock);
+ isd->isd_dying = true;
+ mutex_exit(&isd->isd_lock);
+ callout_halt(&isd->isd_ch, NULL);
+ workqueue_wait(if_slowtimo_wq, &isd->isd_work);
+ callout_destroy(&isd->isd_ch);
+ mutex_destroy(&isd->isd_lock);
+ kmem_free(isd, sizeof(*isd));
+
+ ifp->if_slowtimo_data = NULL; /* paraonia */
+ ifp->if_slowtimo = NULL; /* paranoia */
}
if_deferred_start_destroy(ifp);
@@ -2651,24 +2682,42 @@
* call the appropriate interface routine on expiration.
*/
static void
-if_slowtimo(void *arg)
+if_slowtimo_intr(void *arg)
{
- void (*slowtimo)(struct ifnet *);
struct ifnet *ifp = arg;
- int s;
-
- slowtimo = ifp->if_slowtimo;
- if (__predict_false(slowtimo == NULL))
- return;
-
- s = splnet();
- if (ifp->if_timer != 0 && --ifp->if_timer == 0)
- (*slowtimo)(ifp);
-
- splx(s);
-
- if (__predict_true(ifp->if_slowtimo != NULL))
- callout_schedule(ifp->if_slowtimo_ch, hz / IFNET_SLOWHZ);
+ struct if_slowtimo_data *isd = ifp->if_slowtimo_data;
+
+ mutex_enter(&isd->isd_lock);
+ if (!isd->isd_dying) {
+ if (ifp->if_timer != 0 &&
+ --ifp->if_timer == 0 &&
+ !isd->isd_queued) {
+ isd->isd_queued = true;
+ workqueue_enqueue(if_slowtimo_wq, &isd->isd_work,
+ NULL);
+ } else {
+ callout_schedule(&isd->isd_ch, hz / IFNET_SLOWHZ);
+ }
+ }
+ mutex_exit(&isd->isd_lock);
+}
+
+static void
+if_slowtimo_work(struct work *work, void *arg)
+{
+ struct if_slowtimo_data *isd =
+ container_of(work, struct if_slowtimo_data, isd_work);
+ struct ifnet *ifp = isd->isd_ifp;
+
+ KERNEL_LOCK(1, NULL);
+ (*ifp->if_slowtimo)(ifp);
+ KERNEL_UNLOCK_ONE(NULL);
+
+ mutex_enter(&isd->isd_lock);
+ isd->isd_queued = false;
+ if (!isd->isd_dying)
+ callout_schedule(&isd->isd_ch, hz / IFNET_SLOWHZ);
+ mutex_exit(&isd->isd_lock);
}
/*
diff -r 270d67592e08 -r ec9e647db392 sys/net/if.h
--- a/sys/net/if.h Sat Aug 20 10:55:27 2022 +0000
+++ b/sys/net/if.h Sat Aug 20 11:09:24 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if.h,v 1.299 2022/07/28 15:15:29 skrll Exp $ */
+/* $NetBSD: if.h,v 1.300 2022/08/20 11:09:24 riastradh Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -414,7 +414,7 @@
kmutex_t *if_ioctl_lock; /* :: */
char *if_description; /* i: interface description */
#ifdef _KERNEL /* XXX kvm(3) */
- struct callout *if_slowtimo_ch;/* :: */
+ struct if_slowtimo_data *if_slowtimo_data; /* :: */
struct krwlock *if_afdata_lock;/* :: */
struct if_percpuq
*if_percpuq; /* :: we should remove it in the future */
Home |
Main Index |
Thread Index |
Old Index