summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorozaki-r <ozaki-r@NetBSD.org>2016-02-15 08:08:04 +0000
committerozaki-r <ozaki-r@NetBSD.org>2016-02-15 08:08:04 +0000
commit2e786f661ff47ee7941bb3e9fc6b4559ea0de228 (patch)
tree621211e0dc751035a641d6d001c5abe2556cbd02
parent3c620b7c7c7d0b1928503deca17a67c8b29139d0 (diff)
Run if_link_state_change in softint
if_link_state_change can execute the network stack that is expected to not run in hardware interrupt (at least now), however network drivers may call it in hardware interrupt. Avoid that by introducing a new softint for if_link_state_change. The original patch is provided by mlelstv@ and tweaked a bit by me. Should fix PR kern/50602.
-rw-r--r--sys/net/if.c35
-rw-r--r--sys/net/if.h4
2 files changed, 33 insertions, 6 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index bd158bd315c..3b2ebe95725 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if.c,v 1.323 2016/02/09 08:32:12 ozaki-r Exp $ */
+/* $NetBSD: if.c,v 1.324 2016/02/15 08:08:04 ozaki-r 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.323 2016/02/09 08:32:12 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.324 2016/02/15 08:08:04 ozaki-r Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -200,6 +200,7 @@ static void if_attachdomain1(struct ifnet *);
static int ifconf(u_long, void *);
static int if_clone_create(const char *);
static int if_clone_destroy(const char *);
+static void if_link_state_change_si(void *);
struct if_percpuq {
struct ifnet *ipq_ifp;
@@ -602,6 +603,7 @@ if_initialize(ifnet_t *ifp)
ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */
ifp->if_link_state = LINK_STATE_UNKNOWN;
+ ifp->if_old_link_state = LINK_STATE_UNKNOWN;
ifp->if_capenable = 0;
ifp->if_csum_flags_tx = 0;
@@ -627,6 +629,10 @@ if_initialize(ifnet_t *ifp)
IF_AFDATA_LOCK_INIT(ifp);
+ ifp->if_link_si = softint_establish(SOFTINT_NET, if_link_state_change_si, ifp);
+ if (ifp->if_link_si == NULL)
+ panic("%s: softint_establish() failed", __func__);
+
if_getindex(ifp);
}
@@ -1045,6 +1051,9 @@ again:
IF_AFDATA_LOCK_DESTROY(ifp);
+ softint_disestablish(ifp->if_link_si);
+ ifp->if_link_si = NULL;
+
/*
* remove packets that came from ifp, from software interrupt queues.
*/
@@ -1562,8 +1571,6 @@ void
if_link_state_change(struct ifnet *ifp, int link_state)
{
int s;
- int old_link_state;
- struct domain *dp;
s = splnet();
if (ifp->if_link_state == link_state) {
@@ -1571,8 +1578,26 @@ if_link_state_change(struct ifnet *ifp, int link_state)
return;
}
- old_link_state = ifp->if_link_state;
ifp->if_link_state = link_state;
+ softint_schedule(ifp->if_link_si);
+
+ splx(s);
+}
+
+
+static void
+if_link_state_change_si(void *arg)
+{
+ struct ifnet *ifp = arg;
+ int s;
+ int link_state, old_link_state;
+ struct domain *dp;
+
+ s = splnet();
+ link_state = ifp->if_link_state;
+ old_link_state = ifp->if_old_link_state;
+ ifp->if_old_link_state = ifp->if_link_state;
+
#ifdef DEBUG
log(LOG_DEBUG, "%s: link state %s (was %s)\n", ifp->if_xname,
link_state == LINK_STATE_UP ? "UP" :
diff --git a/sys/net/if.h b/sys/net/if.h
index e85b29c7374..11048ca415a 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if.h,v 1.195 2016/02/09 08:32:12 ozaki-r Exp $ */
+/* $NetBSD: if.h,v 1.196 2016/02/15 08:08:04 ozaki-r Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -358,6 +358,8 @@ typedef struct ifnet {
struct krwlock *if_afdata_lock;
#endif
struct if_percpuq *if_percpuq; /* We should remove it in the future */
+ void *if_link_si; /* softint to handle link state changes */
+ int if_old_link_state; /* previous link state */
#endif
} ifnet_t;