From owner-svn-src-head@freebsd.org Mon Nov 28 05:23:59 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7D329C59A8B; Mon, 28 Nov 2016 05:23:59 +0000 (UTC) (envelope-from sephe@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 37F1B1E2D; Mon, 28 Nov 2016 05:23:59 +0000 (UTC) (envelope-from sephe@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAS5NwQw089692; Mon, 28 Nov 2016 05:23:58 GMT (envelope-from sephe@FreeBSD.org) Received: (from sephe@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAS5NwUq089689; Mon, 28 Nov 2016 05:23:58 GMT (envelope-from sephe@FreeBSD.org) Message-Id: <201611280523.uAS5NwUq089689@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: sephe set sender to sephe@FreeBSD.org using -f From: Sepherosa Ziehau Date: Mon, 28 Nov 2016 05:23:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r309227 - head/sys/dev/hyperv/netvsc X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Nov 2016 05:23:59 -0000 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 { \