From 66fdad6aa8f2c57765debbd4bf50327aadbdbde5 Mon Sep 17 00:00:00 2001 From: yamaguchi Date: Fri, 18 Sep 2020 09:53:50 +0000 Subject: [PATCH] Do pppoe_timeout() in thread context OKed by knakahara@n.o fix port-amd64/55661 --- sys/net/if_pppoe.c | 60 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/sys/net/if_pppoe.c b/sys/net/if_pppoe.c index 4ec3d38e9dde..e0595a2cdb49 100644 --- a/sys/net/if_pppoe.c +++ b/sys/net/if_pppoe.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_pppoe.c,v 1.150 2020/09/18 09:48:56 yamaguchi Exp $ */ +/* $NetBSD: if_pppoe.c,v 1.151 2020/09/18 09:53:50 yamaguchi Exp $ */ /* * Copyright (c) 2002, 2008 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.150 2020/09/18 09:48:56 yamaguchi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.151 2020/09/18 09:53:50 yamaguchi Exp $"); #ifdef _KERNEL_OPT #include "pppoe.h" @@ -41,6 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.150 2020/09/18 09:48:56 yamaguchi Exp #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.150 2020/09/18 09:48:56 yamaguchi Exp #include #include #include +#include #include #include @@ -173,7 +175,10 @@ struct pppoe_softc { uint8_t *sc_hunique; /* content of host unique we must echo back */ size_t sc_hunique_len; /* length of host unique */ #endif - callout_t sc_timeout; /* timeout while not in session state */ + callout_t sc_timeout; /* timeout while not in session state */ + struct workqueue *sc_timeout_wq; /* workqueue for timeout */ + struct work sc_timeout_wk; + u_int sc_timeout_scheduled; int sc_padi_retried; /* number of PADI retries already done */ int sc_padr_retried; /* number of PADR retries already done */ krwlock_t sc_lock; /* lock of sc_state, sc_session, and sc_eth_if */ @@ -209,7 +214,10 @@ static int pppoe_transmit(struct ifnet *, struct mbuf *); static void pppoe_clear_softc(struct pppoe_softc *, const char *); /* internal timeout handling */ -static void pppoe_timeout(void *); +static void pppoe_timeout_co(void *); +static void pppoe_timeout_co_halt(void *); +static void pppoe_timeout_wk(struct work *, void *); +static void pppoe_timeout(struct pppoe_softc *); /* sending actual protocol controll packets */ static int pppoe_send_padi(struct pppoe_softc *); @@ -349,8 +357,16 @@ pppoe_clone_create(struct if_clone *ifc, int unit) /* changed to real address later */ memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest)); + rv = workqueue_create(&sc->sc_timeout_wq, + sc->sc_sppp.pp_if.if_xname, pppoe_timeout_wk, sc, + PRI_SOFTNET, IPL_SOFTNET, 0); + if (rv != 0) { + free(sc, M_DEVBUF); + return rv; + } + callout_init(&sc->sc_timeout, CALLOUT_MPSAFE); - callout_setfunc(&sc->sc_timeout, pppoe_timeout, sc); + callout_setfunc(&sc->sc_timeout, pppoe_timeout_co, sc); sc->sc_sppp.pp_if.if_start = pppoe_start; #ifdef PPPOE_MPSAFE @@ -362,6 +378,7 @@ pppoe_clone_create(struct if_clone *ifc, int unit) rv = if_initialize(&sc->sc_sppp.pp_if); if (rv != 0) { + workqueue_destroy(sc->sc_timeout_wq); callout_halt(&sc->sc_timeout, NULL); callout_destroy(&sc->sc_timeout); free(sc, M_DEVBUF); @@ -395,6 +412,8 @@ pppoe_clone_destroy(struct ifnet *ifp) rw_enter(&pppoe_softc_list_lock, RW_WRITER); PPPOE_LOCK(sc, RW_WRITER); + callout_setfunc(&sc->sc_timeout, pppoe_timeout_co_halt, sc); + workqueue_wait(sc->sc_timeout_wq, &sc->sc_timeout_wk); callout_halt(&sc->sc_timeout, NULL); LIST_REMOVE(sc, sc_list); @@ -416,6 +435,7 @@ pppoe_clone_destroy(struct ifnet *ifp) if (sc->sc_relay_sid) free(sc->sc_relay_sid, M_DEVBUF); callout_destroy(&sc->sc_timeout); + workqueue_destroy(sc->sc_timeout_wq); PPPOE_UNLOCK(sc); rw_destroy(&sc->sc_lock); @@ -1411,10 +1431,36 @@ pppoe_send_padi(struct pppoe_softc *sc) } static void -pppoe_timeout(void *arg) +pppoe_timeout_co(void *arg) +{ + struct pppoe_softc *sc = (struct pppoe_softc *)arg; + + if (atomic_swap_uint(&sc->sc_timeout_scheduled, 1) != 0) + return; + + workqueue_enqueue(sc->sc_timeout_wq, &sc->sc_timeout_wk, NULL); +} + +static void +pppoe_timeout_co_halt(void *unused __unused) +{ + + /* do nothing to halt callout safely */ +} + +static void +pppoe_timeout_wk(struct work *wk __unused, void *arg) +{ + struct pppoe_softc *sc = (struct pppoe_softc *)arg; + + atomic_swap_uint(&sc->sc_timeout_scheduled, 0); + pppoe_timeout(sc); +} + +static void +pppoe_timeout(struct pppoe_softc *sc) { int retry_wait, err; - struct pppoe_softc *sc = (struct pppoe_softc*)arg; DECLARE_SPLNET_VARIABLE; #ifdef PPPOE_DEBUG