hyperv/hn: Fix detach error handling.

MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D8613
This commit is contained in:
Sepherosa Ziehau 2016-11-28 05:23:57 +00:00
parent f6f2e0ce38
commit 2494d735e2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=309227
3 changed files with 74 additions and 18 deletions

View file

@ -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 @@ hn_nvs_conn_chim(struct hn_softc *sc)
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

View file

@ -296,6 +296,7 @@ static int hn_synth_attach(struct hn_softc *, int);
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, struct vmbus_channel *chan)
* 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 *sc, int *nsubch)
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 mtu)
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;

View file

@ -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 { \