Module Name: src
Committed By: thorpej
Date: Thu Feb 6 23:30:20 UTC 2020
Modified Files:
src/sys/net: if.c if.h
src/sys/netinet: ip_carp.c
Log Message:
Perform link state change processing on a work queue, rather than in a
softint.
To generate a diff of this commit:
cvs rdiff -u -r1.470 -r1.471 src/sys/net/if.c
cvs rdiff -u -r1.280 -r1.281 src/sys/net/if.h
cvs rdiff -u -r1.109 -r1.110 src/sys/netinet/ip_carp.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.470 src/sys/net/if.c:1.471
--- src/sys/net/if.c:1.470 Sat Feb 1 12:54:50 2020
+++ src/sys/net/if.c Thu Feb 6 23:30:19 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: if.c,v 1.470 2020/02/01 12:54:50 riastradh Exp $ */
+/* $NetBSD: if.c,v 1.471 2020/02/06 23:30:19 thorpej 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.470 2020/02/01 12:54:50 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.471 2020/02/06 23:30:19 thorpej Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -180,6 +180,7 @@ static uint64_t index_gen;
kmutex_t ifnet_mtx __cacheline_aligned;
static struct psref_class *ifnet_psref_class __read_mostly;
static pserialize_t ifnet_psz;
+static struct workqueue *ifnet_link_state_wq __read_mostly;
static kmutex_t if_clone_mtx;
@@ -211,7 +212,7 @@ static int ifconf(u_long, void *);
static int if_transmit(struct ifnet *, struct mbuf *);
static int if_clone_create(const char *);
static int if_clone_destroy(const char *);
-static void if_link_state_change_si(void *);
+static void if_link_state_change_work(struct work *, void *);
static void if_up_locked(struct ifnet *);
static void _if_down(struct ifnet *);
static void if_down_deactivated(struct ifnet *);
@@ -298,6 +299,7 @@ ifinit(void)
void
ifinit1(void)
{
+ int error __diagused;
#ifdef NET_MPSAFE
printf("NET_MPSAFE enabled\n");
@@ -310,6 +312,10 @@ ifinit1(void)
ifnet_psz = pserialize_create();
ifnet_psref_class = psref_class_create("ifnet", IPL_SOFTNET);
ifa_psref_class = psref_class_create("ifa", IPL_SOFTNET);
+ error = workqueue_create(&ifnet_link_state_wq, "iflnkst",
+ if_link_state_change_work, NULL, PRI_SOFTNET, IPL_SOFTNET,
+ WQ_MPSAFE);
+ KASSERT(error == 0);
PSLIST_INIT(&ifnet_pslist);
if_indexlim = 8;
@@ -717,17 +723,6 @@ if_initialize(ifnet_t *ifp)
IF_AFDATA_LOCK_INIT(ifp);
- if (if_is_link_state_changeable(ifp)) {
- u_int flags = SOFTINT_NET;
- flags |= if_is_mpsafe(ifp) ? SOFTINT_MPSAFE : 0;
- ifp->if_link_si = softint_establish(flags,
- if_link_state_change_si, ifp);
- if (ifp->if_link_si == NULL) {
- rv = ENOMEM;
- goto fail;
- }
- }
-
PSLIST_ENTRY_INIT(ifp, if_pslist_entry);
PSLIST_INIT(&ifp->if_addr_pslist);
psref_target_init(&ifp->if_psref, ifnet_psref_class);
@@ -1484,11 +1479,6 @@ restart:
IF_AFDATA_LOCK_DESTROY(ifp);
- if (if_is_link_state_changeable(ifp)) {
- softint_disestablish(ifp->if_link_si);
- ifp->if_link_si = NULL;
- }
-
/*
* remove packets that came from ifp, from software interrupt queues.
*/
@@ -2252,7 +2242,7 @@ link_rtrequest(int cmd, struct rtentry *
* - if IFEF_MPSAFE is enabled, if_snd isn't used and lock contentions on
* ifq_lock don't happen
* - if IFEF_MPSAFE is disabled, there is no lock contention on ifq_lock
- * because if_snd, if_link_state_change and if_link_state_change_softint
+ * because if_snd, if_link_state_change and if_link_state_change_process
* are all called with KERNEL_LOCK
*/
#define IF_LINK_STATE_CHANGE_LOCK(ifp) \
@@ -2260,6 +2250,16 @@ link_rtrequest(int cmd, struct rtentry *
#define IF_LINK_STATE_CHANGE_UNLOCK(ifp) \
mutex_exit((ifp)->if_snd.ifq_lock)
+static void
+if_link_state_change_work_schedule(struct ifnet *ifp)
+{
+ if (ifp->if_link_cansched && !ifp->if_link_scheduled) {
+ ifp->if_link_scheduled = true;
+ workqueue_enqueue(ifnet_link_state_wq, &ifp->if_link_work,
+ NULL);
+ }
+}
+
/*
* Handle a change in the interface link state and
* queue notifications.
@@ -2328,7 +2328,7 @@ if_link_state_change(struct ifnet *ifp,
} else
LQ_STORE(ifp->if_link_queue, idx, (uint8_t)link_state);
- softint_schedule(ifp->if_link_si);
+ if_link_state_change_work_schedule(ifp);
out:
IF_LINK_STATE_CHANGE_UNLOCK(ifp);
@@ -2337,8 +2337,8 @@ out:
/*
* Handle interface link state change notifications.
*/
-void
-if_link_state_change_softint(struct ifnet *ifp, int link_state)
+static void
+if_link_state_change_process(struct ifnet *ifp, int link_state)
{
struct domain *dp;
int s = splnet();
@@ -2409,32 +2409,34 @@ if_link_state_change_softint(struct ifne
* Process the interface link state change queue.
*/
static void
-if_link_state_change_si(void *arg)
+if_link_state_change_work(struct work *work, void *arg)
{
- struct ifnet *ifp = arg;
+ struct ifnet *ifp = container_of(work, struct ifnet, if_link_work);
int s;
uint8_t state;
bool schedule;
- SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
+ KERNEL_LOCK_UNLESS_NET_MPSAFE();
s = splnet();
/* Pop a link state change from the queue and process it. */
IF_LINK_STATE_CHANGE_LOCK(ifp);
+ ifp->if_link_scheduled = false;
LQ_POP(ifp->if_link_queue, state);
IF_LINK_STATE_CHANGE_UNLOCK(ifp);
- if_link_state_change_softint(ifp, state);
+ if_link_state_change_process(ifp, state);
/* If there is a link state change to come, schedule it. */
IF_LINK_STATE_CHANGE_LOCK(ifp);
schedule = (LQ_ITEM(ifp->if_link_queue, 0) != LINK_STATE_UNSET);
IF_LINK_STATE_CHANGE_UNLOCK(ifp);
+
if (schedule)
- softint_schedule(ifp->if_link_si);
+ if_link_state_change_work_schedule(ifp);
splx(s);
- SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
+ KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
}
/*
@@ -2517,6 +2519,11 @@ _if_down(struct ifnet *ifp)
pserialize_read_exit(s);
curlwp_bindx(bound);
+ IF_LINK_STATE_CHANGE_LOCK(ifp);
+ ifp->if_link_cansched = false;
+ workqueue_wait(ifnet_link_state_wq, &ifp->if_link_work);
+ IF_LINK_STATE_CHANGE_UNLOCK(ifp);
+
IFQ_PURGE(&ifp->if_snd);
#if NCARP > 0
if (ifp->if_carp)
@@ -2589,6 +2596,10 @@ if_up_locked(struct ifnet *ifp)
if (dp->dom_if_up)
dp->dom_if_up(ifp);
}
+
+ IF_LINK_STATE_CHANGE_LOCK(ifp);
+ ifp->if_link_cansched = true;
+ IF_LINK_STATE_CHANGE_UNLOCK(ifp);
}
/*
Index: src/sys/net/if.h
diff -u src/sys/net/if.h:1.280 src/sys/net/if.h:1.281
--- src/sys/net/if.h:1.280 Sat Feb 1 21:59:39 2020
+++ src/sys/net/if.h Thu Feb 6 23:30:19 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: if.h,v 1.280 2020/02/01 21:59:39 thorpej Exp $ */
+/* $NetBSD: if.h,v 1.281 2020/02/06 23:30:19 thorpej Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -229,6 +229,7 @@ struct ifqueue {
#include <sys/percpu.h>
#include <sys/callout.h>
#include <sys/rwlock.h>
+#include <sys/workqueue.h>
#endif /* _KERNEL */
@@ -402,8 +403,12 @@ typedef struct ifnet {
struct krwlock *if_afdata_lock;/* :: */
struct if_percpuq
*if_percpuq; /* :: we should remove it in the future */
- void *if_link_si; /* :: softint to handle link state changes */
+ struct work if_link_work; /* q: linkage on link state work queue */
uint16_t if_link_queue; /* q: masked link state change queue */
+ /* q: is link state work scheduled? */
+ bool if_link_scheduled;
+ /* q: can link state work be scheduled? */
+ bool if_link_cansched;
struct pslist_entry
if_pslist_entry;/* i: */
struct psref_target
@@ -1125,7 +1130,6 @@ void if_detach(struct ifnet *);
void if_down(struct ifnet *);
void if_down_locked(struct ifnet *);
void if_link_state_change(struct ifnet *, int);
-void if_link_state_change_softint(struct ifnet *, int);
void if_up(struct ifnet *);
void ifinit(void);
void ifinit1(void);
Index: src/sys/netinet/ip_carp.c
diff -u src/sys/netinet/ip_carp.c:1.109 src/sys/netinet/ip_carp.c:1.110
--- src/sys/netinet/ip_carp.c:1.109 Tue Feb 4 05:46:32 2020
+++ src/sys/netinet/ip_carp.c Thu Feb 6 23:30:20 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_carp.c,v 1.109 2020/02/04 05:46:32 thorpej Exp $ */
+/* $NetBSD: ip_carp.c,v 1.110 2020/02/06 23:30:20 thorpej Exp $ */
/* $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $ */
/*
@@ -33,7 +33,7 @@
#endif
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.109 2020/02/04 05:46:32 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.110 2020/02/06 23:30:20 thorpej Exp $");
/*
* TODO:
@@ -2265,13 +2265,7 @@ carp_update_link_state(struct carp_softc
? LINK_STATE_DOWN : LINK_STATE_UNKNOWN;
break;
}
- /*
- * The lock is needed to serialize a call of
- * if_link_state_change_softint from here and a call from softint.
- */
- KERNEL_LOCK(1, NULL);
- if_link_state_change_softint(&sc->sc_if, link_state);
- KERNEL_UNLOCK_ONE(NULL);
+ if_link_state_change(&sc->sc_if, link_state);
}
void