Module Name:    src
Committed By:   yamaguchi
Date:           Thu Sep 17 06:34:43 UTC 2020

Modified Files:
        src/sys/dev/pci: if_iavf.c

Log Message:
Fix a panic caused while detaching iavf(4)

The sequence of the panic is follow:
  1. failed to disable queues in iavf_stop()
  2. release ec->ec_lock in ether_ifdetach()
  3. do reset scheduled at iavf_stop()
  4. acquire ec->ec_lock in iavf_reset_finish()
    - panic

reviewed by knakahara@n.o, thanks.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/pci/if_iavf.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/dev/pci/if_iavf.c
diff -u src/sys/dev/pci/if_iavf.c:1.5 src/sys/dev/pci/if_iavf.c:1.6
--- src/sys/dev/pci/if_iavf.c:1.5	Thu Sep 10 03:20:08 2020
+++ src/sys/dev/pci/if_iavf.c	Thu Sep 17 06:34:43 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iavf.c,v 1.5 2020/09/10 03:20:08 yamaguchi Exp $	*/
+/*	$NetBSD: if_iavf.c,v 1.6 2020/09/17 06:34:43 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2013-2015, Intel Corporation
@@ -75,7 +75,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iavf.c,v 1.5 2020/09/10 03:20:08 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iavf.c,v 1.6 2020/09/17 06:34:43 yamaguchi Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -94,6 +94,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_iavf.c,v 
 #include <sys/queue.h>
 #include <sys/syslog.h>
 #include <sys/workqueue.h>
+#include <sys/xcall.h>
 
 #include <net/bpf.h>
 #include <net/if.h>
@@ -626,6 +627,13 @@ static struct iavf_module_params iavf_pa
 #define iavf_allqueues(_sc)	((1 << ((_sc)->sc_nqueue_pairs)) - 1)
 
 static inline void
+iavf_intr_barrier(void)
+{
+
+	/* make all interrupt handler finished */
+	xc_barrier(0);
+}
+static inline void
 iavf_intr_enable(struct iavf_softc *sc)
 {
 
@@ -965,38 +973,40 @@ iavf_detach(device_t self, int flags)
 		return 0;
 
 	iavf_stop(ifp, 1);
-	ether_ifdetach(ifp);
-	if_detach(ifp);
-	ifmedia_fini(&sc->sc_media);
-	if_percpuq_destroy(sc->sc_ipq);
-
-	iavf_intr_disable(sc);
-
-	mutex_enter(&sc->sc_adminq_lock);
-	mutex_exit(&sc->sc_adminq_lock);
 
 	/*
 	 * set a dummy function to halt callout safely
 	 * even if a workqueue entry calls callout_schedule()
 	 */
 	callout_setfunc(&sc->sc_tick, iavf_tick_halt, sc);
-
 	iavf_work_wait(sc->sc_workq, &sc->sc_reset_task);
-	iavf_work_wait(sc->sc_workq, &sc->sc_arq_refill);
 	iavf_work_wait(sc->sc_workq, &sc->sc_wdto_task);
-	iavf_workq_destroy(sc->sc_workq);
-	sc->sc_workq = NULL;
 
 	callout_halt(&sc->sc_tick, NULL);
 	callout_destroy(&sc->sc_tick);
 
+	/* detach the I/F before stop adminq due to callbacks */
+	ether_ifdetach(ifp);
+	if_detach(ifp);
+	ifmedia_fini(&sc->sc_media);
+	if_percpuq_destroy(sc->sc_ipq);
+
+	iavf_intr_disable(sc);
+	iavf_intr_barrier();
+	iavf_work_wait(sc->sc_workq, &sc->sc_arq_refill);
+
+	mutex_enter(&sc->sc_adminq_lock);
 	iavf_cleanup_admin_queue(sc);
+	mutex_exit(&sc->sc_adminq_lock);
 	iavf_aqb_clean(&sc->sc_atq_idle, sc->sc_dmat);
 	iavf_aqb_clean(&sc->sc_arq_idle, sc->sc_dmat);
 	iavf_dmamem_free(sc->sc_dmat, &sc->sc_arq);
 	iavf_dmamem_free(sc->sc_dmat, &sc->sc_atq);
 	cv_destroy(&sc->sc_adminq_cv);
 
+	iavf_workq_destroy(sc->sc_workq);
+	sc->sc_workq = NULL;
+
 	iavf_queue_pairs_free(sc);
 	iavf_teardown_interrupts(sc);
 	iavf_teardown_sysctls(sc);

Reply via email to