Do pppoe_timeout() in thread context

OKed by knakahara@n.o
fix port-amd64/55661
This commit is contained in:
yamaguchi 2020-09-18 09:53:50 +00:00
parent 4acbb1f5ae
commit 66fdad6aa8
1 changed files with 53 additions and 7 deletions

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/atomic.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
@ -57,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.150 2020/09/18 09:48:56 yamaguchi Exp
#include <sys/mutex.h>
#include <sys/psref.h>
#include <sys/cprng.h>
#include <sys/workqueue.h>
#include <net/if.h>
#include <net/if_types.h>
@ -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