Index: sys/dev/hyperv/include/vmbus.h =================================================================== --- sys/dev/hyperv/include/vmbus.h +++ sys/dev/hyperv/include/vmbus.h @@ -116,6 +116,7 @@ }; struct vmbus_channel; +struct vmbus_xact_ctx; struct hyperv_guid; struct task; struct taskqueue; @@ -138,6 +139,9 @@ void vmbus_chan_intr_drain(struct vmbus_channel *chan); void vmbus_chan_run_task(struct vmbus_channel *chan, struct task *task); +void vmbus_chan_set_orphan(struct vmbus_channel *chan, + struct vmbus_xact_ctx *); +void vmbus_chan_unset_orphan(struct vmbus_channel *chan); int vmbus_chan_gpadl_connect(struct vmbus_channel *chan, bus_addr_t paddr, int size, uint32_t *gpadl); Index: sys/dev/hyperv/vmbus/vmbus_chan.c =================================================================== --- sys/dev/hyperv/vmbus/vmbus_chan.c +++ sys/dev/hyperv/vmbus/vmbus_chan.c @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -1115,6 +1116,7 @@ chan->ch_vmbus = sc; mtx_init(&chan->ch_subchan_lock, "vmbus subchan", NULL, MTX_DEF); + sx_init(&chan->ch_orphan_lock, "vmbus chorphan"); TAILQ_INIT(&chan->ch_subchans); vmbus_rxbr_init(&chan->ch_rxbr); vmbus_txbr_init(&chan->ch_txbr); @@ -1133,8 +1135,12 @@ VMBUS_CHAN_ST_ONPRIL | VMBUS_CHAN_ST_ONSUBL | VMBUS_CHAN_ST_ONLIST)) == 0, ("free busy channel")); + KASSERT(chan->ch_orphan_xact == NULL, + ("still has orphan xact installed")); + hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm); mtx_destroy(&chan->ch_subchan_lock); + sx_destroy(&chan->ch_orphan_lock); vmbus_rxbr_deinit(&chan->ch_rxbr); vmbus_txbr_deinit(&chan->ch_txbr); free(chan, M_DEVBUF); @@ -1403,10 +1409,21 @@ mtx_unlock(&sc->vmbus_prichan_lock); } + /* + * NOTE: + * The following processing order is critical: + * Set the REVOKED state flag before orphaning the installed xact. + */ + if (atomic_testandset_int(&chan->ch_stflags, VMBUS_CHAN_ST_REVOKED_SHIFT)) panic("channel has already been revoked"); + sx_xlock(&chan->ch_orphan_lock); + if (chan->ch_orphan_xact != NULL) + vmbus_xact_ctx_orphan(chan->ch_orphan_xact); + sx_xunlock(&chan->ch_orphan_lock); + if (bootverbose) vmbus_chan_printf(chan, "chan%u revoked\n", note->chm_chanid); @@ -1708,3 +1725,21 @@ return (true); return (false); } + +void +vmbus_chan_set_orphan(struct vmbus_channel *chan, struct vmbus_xact_ctx *xact) +{ + + sx_xlock(&chan->ch_orphan_lock); + chan->ch_orphan_xact = xact; + sx_xunlock(&chan->ch_orphan_lock); +} + +void +vmbus_chan_unset_orphan(struct vmbus_channel *chan) +{ + + sx_xlock(&chan->ch_orphan_lock); + chan->ch_orphan_xact = NULL; + sx_xunlock(&chan->ch_orphan_lock); +} Index: sys/dev/hyperv/vmbus/vmbus_chanvar.h =================================================================== --- sys/dev/hyperv/vmbus/vmbus_chanvar.h +++ sys/dev/hyperv/vmbus/vmbus_chanvar.h @@ -33,8 +33,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -138,6 +139,9 @@ struct hyperv_guid ch_guid_type; struct hyperv_guid ch_guid_inst; + struct sx ch_orphan_lock; + struct vmbus_xact_ctx *ch_orphan_xact; + struct sysctl_ctx_list ch_sysctl_ctx; } __aligned(CACHE_LINE_SIZE);