Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Nov 2016 05:23:58 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r309227 - head/sys/dev/hyperv/netvsc
Message-ID:  <201611280523.uAS5NwUq089689@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Mon Nov 28 05:23:57 2016
New Revision: 309227
URL: https://svnweb.freebsd.org/changeset/base/309227

Log:
  hyperv/hn: Fix detach error handling.
  
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D8613

Modified:
  head/sys/dev/hyperv/netvsc/hn_nvs.c
  head/sys/dev/hyperv/netvsc/if_hn.c
  head/sys/dev/hyperv/netvsc/if_hnvar.h

Modified: head/sys/dev/hyperv/netvsc/hn_nvs.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hn_nvs.c	Mon Nov 28 05:15:28 2016	(r309226)
+++ head/sys/dev/hyperv/netvsc/hn_nvs.c	Mon Nov 28 05:23:57 2016	(r309227)
@@ -62,8 +62,8 @@ __FBSDID("$FreeBSD$");
 
 static int			hn_nvs_conn_chim(struct hn_softc *);
 static int			hn_nvs_conn_rxbuf(struct hn_softc *);
-static int			hn_nvs_disconn_chim(struct hn_softc *);
-static int			hn_nvs_disconn_rxbuf(struct hn_softc *);
+static void			hn_nvs_disconn_chim(struct hn_softc *);
+static void			hn_nvs_disconn_rxbuf(struct hn_softc *);
 static int			hn_nvs_conf_ndis(struct hn_softc *, int);
 static int			hn_nvs_init_ndis(struct hn_softc *);
 static int			hn_nvs_doinit(struct hn_softc *, uint32_t);
@@ -308,7 +308,7 @@ cleanup:
 	return (error);
 }
 
-static int
+static void
 hn_nvs_disconn_rxbuf(struct hn_softc *sc)
 {
 	int error;
@@ -328,7 +328,12 @@ hn_nvs_disconn_rxbuf(struct hn_softc *sc
 		if (error) {
 			if_printf(sc->hn_ifp,
 			    "send nvs rxbuf disconn failed: %d\n", error);
-			return (error);
+			/*
+			 * Fine for a revoked channel, since the hypervisor
+			 * does not drain TX bufring for a revoked channel.
+			 */
+			if (!vmbus_chan_is_revoked(sc->hn_prichan))
+				sc->hn_flags |= HN_FLAG_RXBUF_REF;
 		}
 		sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
 
@@ -357,14 +362,13 @@ hn_nvs_disconn_rxbuf(struct hn_softc *sc
 		if (error) {
 			if_printf(sc->hn_ifp,
 			    "rxbuf gpadl disconn failed: %d\n", error);
-			return (error);
+			sc->hn_flags |= HN_FLAG_RXBUF_REF;
 		}
 		sc->hn_rxbuf_gpadl = 0;
 	}
-	return (0);
 }
 
-static int
+static void
 hn_nvs_disconn_chim(struct hn_softc *sc)
 {
 	int error;
@@ -384,7 +388,12 @@ hn_nvs_disconn_chim(struct hn_softc *sc)
 		if (error) {
 			if_printf(sc->hn_ifp,
 			    "send nvs chim disconn failed: %d\n", error);
-			return (error);
+			/*
+			 * Fine for a revoked channel, since the hypervisor
+			 * does not drain TX bufring for a revoked channel.
+			 */
+			if (!vmbus_chan_is_revoked(sc->hn_prichan))
+				sc->hn_flags |= HN_FLAG_CHIM_REF;
 		}
 		sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
 
@@ -414,7 +423,7 @@ hn_nvs_disconn_chim(struct hn_softc *sc)
 		if (error) {
 			if_printf(sc->hn_ifp,
 			    "chim gpadl disconn failed: %d\n", error);
-			return (error);
+			sc->hn_flags |= HN_FLAG_CHIM_REF;
 		}
 		sc->hn_chim_gpadl = 0;
 	}
@@ -423,7 +432,6 @@ hn_nvs_disconn_chim(struct hn_softc *sc)
 		free(sc->hn_chim_bmap, M_DEVBUF);
 		sc->hn_chim_bmap = NULL;
 	}
-	return (0);
 }
 
 static int

Modified: head/sys/dev/hyperv/netvsc/if_hn.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hn.c	Mon Nov 28 05:15:28 2016	(r309226)
+++ head/sys/dev/hyperv/netvsc/if_hn.c	Mon Nov 28 05:23:57 2016	(r309227)
@@ -296,6 +296,7 @@ static int			hn_synth_attach(struct hn_s
 static void			hn_synth_detach(struct hn_softc *);
 static int			hn_synth_alloc_subchans(struct hn_softc *,
 				    int *);
+static bool			hn_synth_attachable(const struct hn_softc *);
 static void			hn_suspend(struct hn_softc *);
 static void			hn_suspend_data(struct hn_softc *);
 static void			hn_suspend_mgmt(struct hn_softc *);
@@ -3249,7 +3250,10 @@ hn_destroy_rx_data(struct hn_softc *sc)
 	int i;
 
 	if (sc->hn_rxbuf != NULL) {
-		hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
+		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
+			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
+		else
+			device_printf(sc->hn_dev, "RXBUF is referenced\n");
 		sc->hn_rxbuf = NULL;
 	}
 
@@ -3261,7 +3265,12 @@ hn_destroy_rx_data(struct hn_softc *sc)
 
 		if (rxr->hn_br == NULL)
 			continue;
-		hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
+		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
+			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
+		} else {
+			device_printf(sc->hn_dev,
+			    "%dth channel bufring is referenced", i);
+		}
 		rxr->hn_br = NULL;
 
 #if defined(INET) || defined(INET6)
@@ -3730,7 +3739,12 @@ hn_destroy_tx_data(struct hn_softc *sc)
 	int i;
 
 	if (sc->hn_chim != NULL) {
-		hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
+		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
+			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
+		} else {
+			device_printf(sc->hn_dev,
+			    "chimney sending buffer is referenced");
+		}
 		sc->hn_chim = NULL;
 	}
 
@@ -4214,7 +4228,7 @@ static void
 hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
 {
 	struct hn_rx_ring *rxr;
-	int idx;
+	int idx, error;
 
 	idx = vmbus_chan_subidx(chan);
 
@@ -4243,7 +4257,16 @@ hn_chan_detach(struct hn_softc *sc, stru
 	 * NOTE:
 	 * Channel closing does _not_ destroy the target channel.
 	 */
-	vmbus_chan_close(chan);
+	error = vmbus_chan_close_direct(chan);
+	if (error == EISCONN) {
+		if_printf(sc->hn_ifp, "chan%u subidx%u "
+		    "bufring is connected after being closed\n",
+		    vmbus_chan_id(chan), vmbus_chan_subidx(chan));
+		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
+	} else if (error) {
+		if_printf(sc->hn_ifp, "chan%u subidx%u close failed: %d\n",
+		    vmbus_chan_id(chan), vmbus_chan_subidx(chan), error);
+	}
 }
 
 static int
@@ -4373,6 +4396,23 @@ hn_synth_alloc_subchans(struct hn_softc 
 	return (0);
 }
 
+static bool
+hn_synth_attachable(const struct hn_softc *sc)
+{
+	int i;
+
+	if (sc->hn_flags & HN_FLAG_ERRORS)
+		return (false);
+
+	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
+		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
+
+		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
+			return (false);
+	}
+	return (true);
+}
+
 static int
 hn_synth_attach(struct hn_softc *sc, int mtu)
 {
@@ -4383,6 +4423,9 @@ hn_synth_attach(struct hn_softc *sc, int
 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
 	    ("synthetic parts were attached"));
 
+	if (!hn_synth_attachable(sc))
+		return (ENXIO);
+
 	/* Save capabilities for later verification. */
 	old_caps = sc->hn_caps;
 	sc->hn_caps = 0;

Modified: head/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hnvar.h	Mon Nov 28 05:15:28 2016	(r309226)
+++ head/sys/dev/hyperv/netvsc/if_hnvar.h	Mon Nov 28 05:23:57 2016	(r309227)
@@ -91,7 +91,8 @@ struct hn_rx_ring {
 #define HN_TRUST_HCSUM_TCP	0x0002
 #define HN_TRUST_HCSUM_UDP	0x0004
 
-#define HN_RX_FLAG_ATTACHED	0x1
+#define HN_RX_FLAG_ATTACHED	0x0001
+#define HN_RX_FLAG_BR_REF	0x0002
 
 struct hn_tx_ring {
 #ifndef HN_USE_TXDESC_BUFRING
@@ -162,8 +163,8 @@ struct hn_tx_ring {
 	struct sysctl_oid *hn_tx_sysctl_tree;
 } __aligned(CACHE_LINE_SIZE);
 
-#define HN_TX_FLAG_ATTACHED	0x1
-#define HN_TX_FLAG_HASHVAL	0x2	/* support HASHVAL pktinfo */
+#define HN_TX_FLAG_ATTACHED	0x0001
+#define HN_TX_FLAG_HASHVAL	0x0002	/* support HASHVAL pktinfo */
 
 /*
  * Device-specific softc structure
@@ -237,6 +238,10 @@ struct hn_softc {
 #define HN_FLAG_HAS_RSSIND		0x0008
 #define HN_FLAG_SYNTH_ATTACHED		0x0010
 #define HN_FLAG_NO_SLEEPING		0x0020
+#define HN_FLAG_RXBUF_REF		0x0040
+#define HN_FLAG_CHIM_REF		0x0080
+
+#define HN_FLAG_ERRORS			(HN_FLAG_RXBUF_REF | HN_FLAG_CHIM_REF)
 
 #define HN_NO_SLEEPING(sc)			\
 do {						\



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611280523.uAS5NwUq089689>