diff options
| author | ozaki-r <ozaki-r@NetBSD.org> | 2016-02-15 08:08:04 +0000 |
|---|---|---|
| committer | ozaki-r <ozaki-r@NetBSD.org> | 2016-02-15 08:08:04 +0000 |
| commit | 2e786f661ff47ee7941bb3e9fc6b4559ea0de228 (patch) | |
| tree | 621211e0dc751035a641d6d001c5abe2556cbd02 | |
| parent | 3c620b7c7c7d0b1928503deca17a67c8b29139d0 (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.c | 35 | ||||
| -rw-r--r-- | sys/net/if.h | 4 |
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; |
