Module Name:    src
Committed By:   yamaguchi
Date:           Fri Sep 18 09:53:50 UTC 2020

Modified Files:
        src/sys/net: if_pppoe.c

Log Message:
Do pppoe_timeout() in thread context

OKed by knakahara@n.o
fix port-amd64/55661


To generate a diff of this commit:
cvs rdiff -u -r1.150 -r1.151 src/sys/net/if_pppoe.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_pppoe.c
diff -u src/sys/net/if_pppoe.c:1.150 src/sys/net/if_pppoe.c:1.151
--- src/sys/net/if_pppoe.c:1.150	Fri Sep 18 09:48:56 2020
+++ src/sys/net/if_pppoe.c	Fri Sep 18 09:53:50 2020
@@ -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
 #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
 #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 *
 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,
 	/* 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,
 
 	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

Reply via email to