Module Name:    src
Committed By:   jdolecek
Date:           Mon Apr  6 16:43:34 UTC 2020

Modified Files:
        src/sys/arch/xen/xen: if_xennet_xenbus.c

Log Message:
make a pass on locking, replacing spl*() calls with mutexes:
- sc_tx_lock covers any access to tx list, tx ring, and writes to
  if_flags and if_itimer
- sc_rx_lock covers any access to rx list, tx ring, and free tx counter

fix suspend and detach to work again - recent softintr changes made
xennet_tx_complete() not actually being called, because the call
in xennet_handler() was after IFF_RUNNING check; now it's called
directly rather than triggering softint, with updates locking it's safe

enable DVF_DETACH_SHUTDOWN for xennet(4), though the call only
triggers notification to backend to close, leaves actual detach to
xenwatch_thread


To generate a diff of this commit:
cvs rdiff -u -r1.104 -r1.105 src/sys/arch/xen/xen/if_xennet_xenbus.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/arch/xen/xen/if_xennet_xenbus.c
diff -u src/sys/arch/xen/xen/if_xennet_xenbus.c:1.104 src/sys/arch/xen/xen/if_xennet_xenbus.c:1.105
--- src/sys/arch/xen/xen/if_xennet_xenbus.c:1.104	Mon Apr  6 15:30:52 2020
+++ src/sys/arch/xen/xen/if_xennet_xenbus.c	Mon Apr  6 16:43:34 2020
@@ -1,4 +1,4 @@
-/*      $NetBSD: if_xennet_xenbus.c,v 1.104 2020/04/06 15:30:52 jdolecek Exp $      */
+/*      $NetBSD: if_xennet_xenbus.c,v 1.105 2020/04/06 16:43:34 jdolecek Exp $      */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -81,7 +81,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.104 2020/04/06 15:30:52 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.105 2020/04/06 16:43:34 jdolecek Exp $");
 
 #include "opt_xen.h"
 #include "opt_nfs_boot.h"
@@ -194,8 +194,8 @@ struct xennet_xenbus_softc {
 	grant_ref_t sc_tx_ring_gntref;
 	grant_ref_t sc_rx_ring_gntref;
 
-	kmutex_t sc_tx_lock; /* protects free TX list, below */
-	kmutex_t sc_rx_lock; /* protects free RX list, below */
+	kmutex_t sc_tx_lock; /* protects free TX list, TX ring, and ifp */
+	kmutex_t sc_rx_lock; /* protects free RX list, RX ring, and rxreql */
 	struct xennet_txreq sc_txreqs[NET_TX_RING_SIZE];
 	struct xennet_rxreq sc_rxreqs[NET_RX_RING_SIZE];
 	SLIST_HEAD(,xennet_txreq) sc_txreq_head; /* list of free TX requests */
@@ -232,7 +232,6 @@ static void xennet_hex_dump(const unsign
 
 static int  xennet_init(struct ifnet *);
 static void xennet_stop(struct ifnet *, int);
-static void xennet_reset(struct xennet_xenbus_softc *);
 static void xennet_start(struct ifnet *);
 static int  xennet_ioctl(struct ifnet *, u_long, void *);
 static void xennet_watchdog(struct ifnet *);
@@ -242,7 +241,7 @@ static bool xennet_xenbus_resume (device
 
 CFATTACH_DECL3_NEW(xennet, sizeof(struct xennet_xenbus_softc),
    xennet_xenbus_match, xennet_xenbus_attach, xennet_xenbus_detach, NULL,
-   NULL, NULL, /*DVF_DETACH_SHUTDOWN*/0);
+   NULL, NULL, DVF_DETACH_SHUTDOWN);
 
 static int
 xennet_xenbus_match(device_t parent, cfdata_t match, void *aux)
@@ -308,7 +307,7 @@ xennet_xenbus_attach(device_t parent, de
 	/* xenbus ensure 2 devices can't be probed at the same time */
 	if (if_xennetrxbuf_cache_inited == 0) {
 		if_xennetrxbuf_cache = pool_cache_init(PAGE_SIZE, 0, 0, 0,
-		    "xnfrx", NULL, IPL_VM, NULL, NULL, NULL);
+		    "xnfrx", NULL, IPL_NET, NULL, NULL, NULL);
 		if_xennetrxbuf_cache_inited = 1;
 	}
 
@@ -421,22 +420,34 @@ xennet_xenbus_detach(device_t self, int 
 {
 	struct xennet_xenbus_softc *sc = device_private(self);
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
-	int s0;
 	RING_IDX i;
 
+	if ((flags & (DETACH_SHUTDOWN | DETACH_FORCE)) == DETACH_SHUTDOWN) {
+		/* Trigger state transition with backend */
+		xenbus_switch_state(sc->sc_xbusd, NULL, XenbusStateClosing);
+		return EBUSY;
+	}
+
 	DPRINTF(("%s: xennet_xenbus_detach\n", device_xname(self)));
-	s0 = splnet();
+
+	/* stop interface */
 	xennet_stop(ifp, 1);
-	xen_intr_disestablish(sc->sc_ih);
-	/* wait for pending TX to complete, and collect pending RX packets */
-	xennet_handler(sc);
+	if (sc->sc_ih != NULL) {
+		xen_intr_disestablish(sc->sc_ih);
+		sc->sc_ih = NULL;
+	}
+
+	/* collect any outstanding TX responses */
+	mutex_enter(&sc->sc_tx_lock);
+	xennet_tx_complete(sc);
 	while (sc->sc_tx_ring.sring->rsp_prod != sc->sc_tx_ring.rsp_cons) {
-		/* XXXSMP */
-		tsleep(xennet_xenbus_detach, PRIBIO, "xnet_detach", hz/2);
-		xennet_handler(sc);
+		kpause("xndetach", true, hz/2, &sc->sc_tx_lock);
+		xennet_tx_complete(sc);
 	}
-	xennet_free_rx_buffer(sc);
+	mutex_exit(&sc->sc_tx_lock);
 
+	mutex_enter(&sc->sc_rx_lock);
+	xennet_free_rx_buffer(sc);
 	for (i = 0; i < NET_RX_RING_SIZE; i++) {
 		struct xennet_rxreq *rxreq = &sc->sc_rxreqs[i];
 		if (rxreq->rxreq_va != 0) {
@@ -445,6 +456,7 @@ xennet_xenbus_detach(device_t self, int 
 			rxreq->rxreq_va = 0;
 		}
 	}
+	mutex_exit(&sc->sc_rx_lock);
 
 	ether_ifdetach(ifp);
 	if_detach(ifp);
@@ -452,24 +464,26 @@ xennet_xenbus_detach(device_t self, int 
 	/* Unhook the entropy source. */
 	rnd_detach_source(&sc->sc_rnd_source);
 
-	while (xengnt_status(sc->sc_tx_ring_gntref)) {
-		/* XXXSMP */
-		tsleep(xennet_xenbus_detach, PRIBIO, "xnet_txref", hz/2);
-	}
+	/* Wait until the tx/rx rings stop being used by backend */
+	mutex_enter(&sc->sc_tx_lock);
+	while (xengnt_status(sc->sc_tx_ring_gntref))
+		kpause("xntxref", true, hz/2, &sc->sc_tx_lock);
 	xengnt_revoke_access(sc->sc_tx_ring_gntref);
+	mutex_exit(&sc->sc_tx_lock);
 	uvm_km_free(kernel_map, (vaddr_t)sc->sc_tx_ring.sring, PAGE_SIZE,
 	    UVM_KMF_WIRED);
-	while (xengnt_status(sc->sc_rx_ring_gntref)) {
-		/* XXXSMP */
-		tsleep(xennet_xenbus_detach, PRIBIO, "xnet_rxref", hz/2);
-	}
+	mutex_enter(&sc->sc_rx_lock);
+	while (xengnt_status(sc->sc_rx_ring_gntref))
+		kpause("xnrxref", true, hz/2, &sc->sc_rx_lock);
 	xengnt_revoke_access(sc->sc_rx_ring_gntref);
+	mutex_exit(&sc->sc_rx_lock);
 	uvm_km_free(kernel_map, (vaddr_t)sc->sc_rx_ring.sring, PAGE_SIZE,
 	    UVM_KMF_WIRED);
-	splx(s0);
 
 	pmf_device_deregister(self);
 
+	sc->sc_backend_status = BEST_DISCONNECTED;
+
 	DPRINTF(("%s: xennet_xenbus_detach done\n", device_xname(self)));
 	return 0;
 }
@@ -616,7 +630,6 @@ abort_transaction:
 static bool
 xennet_xenbus_suspend(device_t dev, const pmf_qual_t *qual)
 {
-	int s;
 	struct xennet_xenbus_softc *sc = device_private(dev);
 
 	/*
@@ -624,14 +637,14 @@ xennet_xenbus_suspend(device_t dev, cons
 	 * so we do not mask event channel here
 	 */
 
-	s = splnet();
-	/* process any outstanding TX responses, then collect RX packets */
-	xennet_handler(sc);
+	/* collect any outstanding TX responses */
+	mutex_enter(&sc->sc_tx_lock);
+	xennet_tx_complete(sc);
 	while (sc->sc_tx_ring.sring->rsp_prod != sc->sc_tx_ring.rsp_cons) {
-		/* XXXSMP */
-		tsleep(xennet_xenbus_suspend, PRIBIO, "xnet_suspend", hz/2);
-		xennet_handler(sc);
+		kpause("xnsuspend", true, hz/2, &sc->sc_tx_lock);
+		xennet_tx_complete(sc);
 	}
+	mutex_exit(&sc->sc_tx_lock);
 
 	/*
 	 * dom0 may still use references to the grants we gave away
@@ -641,9 +654,11 @@ xennet_xenbus_suspend(device_t dev, cons
 	 */
 
 	sc->sc_backend_status = BEST_SUSPENDED;
-	xen_intr_disestablish(sc->sc_ih);
-
-	splx(s);
+	if (sc->sc_ih != NULL) {
+		/* event already disabled */
+		xen_intr_disestablish(sc->sc_ih);
+		sc->sc_ih = NULL;
+	}
 
 	xenbus_device_suspend(sc->sc_xbusd);
 	aprint_verbose_dev(dev, "removed event channel %d\n", sc->sc_evtchn);
@@ -693,9 +708,10 @@ xennet_alloc_rx_buffer(struct xennet_xen
 	struct xennet_rxreq *req;
 	int otherend_id, notify;
 
+	KASSERT(mutex_owned(&sc->sc_rx_lock));
+
 	otherend_id = sc->sc_xbusd->xbusd_otherend_id;
 
-	KASSERT(mutex_owned(&sc->sc_rx_lock));
 	for (i = 0; sc->sc_free_rxreql != 0; i++) {
 		req  = SLIST_FIRST(&sc->sc_rxreq_head);
 		KASSERT(req != NULL);
@@ -736,7 +752,7 @@ xennet_free_rx_buffer(struct xennet_xenb
 {
 	RING_IDX i;
 
-	mutex_enter(&sc->sc_rx_lock);
+	KASSERT(mutex_owned(&sc->sc_rx_lock));
 
 	DPRINTF(("%s: xennet_free_rx_buffer\n", device_xname(sc->sc_dev)));
 	/* get back memory from RX ring */
@@ -757,7 +773,6 @@ xennet_free_rx_buffer(struct xennet_xenb
 		}
 
 	}
-	mutex_exit(&sc->sc_rx_lock);
 	DPRINTF(("%s: xennet_free_rx_buffer done\n", device_xname(sc->sc_dev)));
 }
 
@@ -767,7 +782,6 @@ xennet_free_rx_buffer(struct xennet_xenb
 static void
 xennet_rx_mbuf_free(struct mbuf *m, void *buf, size_t size, void *arg)
 {
-	int s = splnet();
 	KASSERT(buf == m->m_ext.ext_buf);
 	KASSERT(arg == NULL);
 	KASSERT(m != NULL);
@@ -775,7 +789,6 @@ xennet_rx_mbuf_free(struct mbuf *m, void
 	pool_cache_put_paddr(if_xennetrxbuf_cache,
 	    (void *)va, m->m_ext.ext_paddr);
 	pool_cache_put(mb_cache, m);
-	splx(s);
 };
 
 static void
@@ -812,10 +825,10 @@ xennet_tx_complete(struct xennet_xenbus_
 	DPRINTFN(XEDB_EVENT, ("xennet_tx_complete prod %d cons %d\n",
 	    sc->sc_tx_ring.sring->rsp_prod, sc->sc_tx_ring.rsp_cons));
 
+	KASSERT(mutex_owned(&sc->sc_tx_lock));
 again:
 	resp_prod = sc->sc_tx_ring.sring->rsp_prod;
 	xen_rmb();
-	mutex_enter(&sc->sc_tx_lock);
 	for (i = sc->sc_tx_ring.rsp_cons; i != resp_prod; i++) {
 		req = &sc->sc_txreqs[RING_GET_RESPONSE(&sc->sc_tx_ring, i)->id];
 		KASSERT(req->txreq_id ==
@@ -831,7 +844,6 @@ again:
 		m_freem(req->txreq_m);
 		SLIST_INSERT_HEAD(&sc->sc_txreq_head, req, txreq_next);
 	}
-	mutex_exit(&sc->sc_tx_lock);
 
 	sc->sc_tx_ring.rsp_cons = resp_prod;
 	/* set new event and check for race with rsp_cons update */
@@ -955,8 +967,10 @@ again:
 	RING_FINAL_CHECK_FOR_RESPONSES(&sc->sc_rx_ring, more_to_do);
 	mutex_exit(&sc->sc_rx_lock);
 
-	if (more_to_do)
+	if (more_to_do) {
+		DPRINTF(("%s: %s more_to_do\n", ifp->if_xname, __func__));
 		goto again;
+	}
 
 	return 1;
 }
@@ -978,15 +992,17 @@ xennet_start(struct ifnet *ifp)
 	int notify;
 	int do_notify = 0;
 
-	if ((ifp->if_flags & IFF_RUNNING) == 0)
+	mutex_enter(&sc->sc_tx_lock);
+
+	if ((ifp->if_flags & IFF_RUNNING) == 0) {
+		mutex_exit(&sc->sc_tx_lock);
 		return;
+	}
 
 	rnd_add_uint32(&sc->sc_rnd_source, sc->sc_tx_ring.req_prod_pvt);
 
 	xennet_tx_complete(sc);
 
-	mutex_enter(&sc->sc_tx_lock);
-
 	req_prod = sc->sc_tx_ring.req_prod_pvt;
 	while (/*CONSTCOND*/1) {
 		uint16_t txflags;
@@ -1159,21 +1175,22 @@ int
 xennet_init(struct ifnet *ifp)
 {
 	struct xennet_xenbus_softc *sc = ifp->if_softc;
-	mutex_enter(&sc->sc_rx_lock);
 
 	DPRINTFN(XEDB_FOLLOW, ("%s: xennet_init()\n",
 	    device_xname(sc->sc_dev)));
 
+	mutex_enter(&sc->sc_tx_lock);
 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
+		mutex_enter(&sc->sc_rx_lock);
 		sc->sc_rx_ring.sring->rsp_event =
 		    sc->sc_rx_ring.rsp_cons + 1;
+		mutex_exit(&sc->sc_rx_lock);
 		hypervisor_unmask_event(sc->sc_evtchn);
 		hypervisor_notify_via_evtchn(sc->sc_evtchn);
-		xennet_reset(sc);
 	}
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_timer = 0;
-	mutex_exit(&sc->sc_rx_lock);
+	mutex_exit(&sc->sc_tx_lock);
 	return 0;
 }
 
@@ -1182,17 +1199,10 @@ xennet_stop(struct ifnet *ifp, int disab
 {
 	struct xennet_xenbus_softc *sc = ifp->if_softc;
 
+	mutex_enter(&sc->sc_tx_lock);
 	ifp->if_flags &= ~IFF_RUNNING;
+	mutex_exit(&sc->sc_tx_lock);
 	hypervisor_mask_event(sc->sc_evtchn);
-	xennet_reset(sc);
-}
-
-void
-xennet_reset(struct xennet_xenbus_softc *sc)
-{
-
-	DPRINTFN(XEDB_FOLLOW, ("%s: xennet_reset()\n",
-	    device_xname(sc->sc_dev)));
 }
 
 #if defined(NFS_BOOT_BOOTSTATIC)

Reply via email to