Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 5 Jan 2017 04:22:03 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r311359 - in stable/11/sys/dev/hyperv: include vmbus
Message-ID:  <201701050422.v054M33Z074235@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Thu Jan  5 04:22:03 2017
New Revision: 311359
URL: https://svnweb.freebsd.org/changeset/base/311359

Log:
  MFC 309030,309039,309080,309081,309083
  
  309030
      hyperv/vmbus: Set a mark on the revoked channel.
  
      This will be used to fix device detach DEVMETHOD for revoked primary
      channel.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8522
  
  309039
      hyperv/vmbus: Merge free/active locks.
  
      These functions are only used by management stuffs, so there are
      no needs to introduce extra complexity.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8524
  
  309080
      hyperv/vmbus: Implement orphan support for transaction API
  
      It will be used to fix the primary channel revocation support.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8525
  
  309081
      hyperv/vmbus: Fix the primary channel revoking on vmbus side.
  
      Drivers can now use vmbus_chan_{is_revoked,set_orphan,unset_orphan}() and
      vmbus_xact_ctx_orphan() to fix their attach/detach DEVMETHODs for revoked
      primary channels.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8545
  
  309083
      hyperv/vmbus: Fix the multi-channel revoking on vmbus side.
  
      - Reference count the sub-channel when channel offer message is
        processed, so that immediate rescind message on the same channel
        will not race sub-channel open on driver side.
      - Drop the above reference when sub-channel is closed, this closely
        mimics the hypervisor's reaction when primary channel is closed
        on the VM side.  No drivers use sub-channel after primary channel
        is closed.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8546

Modified:
  stable/11/sys/dev/hyperv/include/vmbus.h
  stable/11/sys/dev/hyperv/include/vmbus_xact.h
  stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c
  stable/11/sys/dev/hyperv/vmbus/vmbus_chanvar.h
  stable/11/sys/dev/hyperv/vmbus/vmbus_xact.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/hyperv/include/vmbus.h
==============================================================================
--- stable/11/sys/dev/hyperv/include/vmbus.h	Thu Jan  5 03:42:29 2017	(r311358)
+++ stable/11/sys/dev/hyperv/include/vmbus.h	Thu Jan  5 04:22:03 2017	(r311359)
@@ -116,6 +116,7 @@ struct vmbus_chan_br {
 };
 
 struct vmbus_channel;
+struct vmbus_xact_ctx;
 struct hyperv_guid;
 struct task;
 struct taskqueue;
@@ -138,6 +139,9 @@ void		vmbus_chan_close(struct vmbus_chan
 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);
@@ -172,6 +176,7 @@ int		vmbus_chan_send_prplist(struct vmbu
 uint32_t	vmbus_chan_id(const struct vmbus_channel *chan);
 uint32_t	vmbus_chan_subidx(const struct vmbus_channel *chan);
 bool		vmbus_chan_is_primary(const struct vmbus_channel *chan);
+bool		vmbus_chan_is_revoked(const struct vmbus_channel *chan);
 const struct hyperv_guid *
 		vmbus_chan_guid_inst(const struct vmbus_channel *chan);
 int		vmbus_chan_prplist_nelem(int br_size, int prpcnt_max,

Modified: stable/11/sys/dev/hyperv/include/vmbus_xact.h
==============================================================================
--- stable/11/sys/dev/hyperv/include/vmbus_xact.h	Thu Jan  5 03:42:29 2017	(r311358)
+++ stable/11/sys/dev/hyperv/include/vmbus_xact.h	Thu Jan  5 04:22:03 2017	(r311359)
@@ -39,6 +39,8 @@ struct vmbus_xact_ctx	*vmbus_xact_ctx_cr
 			    size_t req_size, size_t resp_size,
 			    size_t priv_size);
 void			vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx);
+bool			vmbus_xact_ctx_orphan(struct vmbus_xact_ctx *ctx);
+
 struct vmbus_xact	*vmbus_xact_get(struct vmbus_xact_ctx *ctx,
 			    size_t req_len);
 void			vmbus_xact_put(struct vmbus_xact *xact);

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c	Thu Jan  5 03:42:29 2017	(r311358)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c	Thu Jan  5 04:22:03 2017	(r311359)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/stdarg.h>
 
 #include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/hyperv/include/vmbus_xact.h>
 #include <dev/hyperv/vmbus/hyperv_var.h>
 #include <dev/hyperv/vmbus/vmbus_reg.h>
 #include <dev/hyperv/vmbus/vmbus_var.h>
@@ -64,6 +65,7 @@ static void			vmbus_chan_cpu_default(str
 static int			vmbus_chan_release(struct vmbus_channel *);
 static void			vmbus_chan_set_chmap(struct vmbus_channel *);
 static void			vmbus_chan_clear_chmap(struct vmbus_channel *);
+static void			vmbus_chan_detach(struct vmbus_channel *);
 
 static void			vmbus_chan_ins_prilist(struct vmbus_softc *,
 				    struct vmbus_channel *);
@@ -627,6 +629,32 @@ vmbus_chan_gpadl_disconnect(struct vmbus
 }
 
 static void
+vmbus_chan_detach(struct vmbus_channel *chan)
+{
+	int refs;
+
+	KASSERT(chan->ch_refs > 0, ("chan%u: invalid refcnt %d",
+	    chan->ch_id, chan->ch_refs));
+	refs = atomic_fetchadd_int(&chan->ch_refs, -1);
+#ifdef INVARIANTS
+	if (VMBUS_CHAN_ISPRIMARY(chan)) {
+		KASSERT(refs == 1, ("chan%u: invalid refcnt %d for prichan",
+		    chan->ch_id, refs + 1));
+	}
+#endif
+	if (refs == 1) {
+		/*
+		 * Detach the target channel.
+		 */
+		if (bootverbose) {
+			vmbus_chan_printf(chan, "chan%u detached\n",
+			    chan->ch_id);
+		}
+		taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_detach_task);
+	}
+}
+
+static void
 vmbus_chan_clrchmap_task(void *xchan, int pending __unused)
 {
 	struct vmbus_channel *chan = xchan;
@@ -751,8 +779,15 @@ vmbus_chan_close(struct vmbus_channel *c
 		int i;
 
 		subchan = vmbus_subchan_get(chan, subchan_cnt);
-		for (i = 0; i < subchan_cnt; ++i)
+		for (i = 0; i < subchan_cnt; ++i) {
 			vmbus_chan_close_internal(subchan[i]);
+			/*
+			 * This sub-channel is referenced, when it is
+			 * linked to the primary channel; drop that
+			 * reference now.
+			 */
+			vmbus_chan_detach(subchan[i]);
+		}
 		vmbus_subchan_rel(subchan, subchan_cnt);
 	}
 
@@ -1113,8 +1148,10 @@ vmbus_chan_alloc(struct vmbus_softc *sc)
 		return NULL;
 	}
 
+	chan->ch_refs = 1;
 	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 +1170,14 @@ vmbus_chan_free(struct vmbus_channel *ch
 	     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"));
+	KASSERT(chan->ch_refs == 0, ("chan%u: invalid refcnt %d",
+	    chan->ch_id, chan->ch_refs));
+
 	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);
@@ -1207,6 +1250,14 @@ vmbus_chan_add(struct vmbus_channel *new
 	    ("new channel is not sub-channel"));
 	KASSERT(prichan != NULL, ("no primary channel"));
 
+	/*
+	 * Reference count this sub-channel; it will be dereferenced
+	 * when this sub-channel is closed.
+	 */
+	KASSERT(newchan->ch_refs == 1, ("chan%u: invalid refcnt %d",
+	    newchan->ch_id, newchan->ch_refs));
+	atomic_add_int(&newchan->ch_refs, 1);
+
 	newchan->ch_prichan = prichan;
 	newchan->ch_dev = prichan->ch_dev;
 
@@ -1220,7 +1271,7 @@ vmbus_chan_add(struct vmbus_channel *new
 	wakeup(prichan);
 done:
 	/*
-	 * Hook this channel up for later rescind.
+	 * Hook this channel up for later revocation.
 	 */
 	mtx_lock(&sc->vmbus_chan_lock);
 	vmbus_chan_ins_list(sc, newchan);
@@ -1353,6 +1404,7 @@ vmbus_chan_msgproc_choffer(struct vmbus_
 	if (error) {
 		device_printf(sc->vmbus_dev, "add chan%u failed: %d\n",
 		    chan->ch_id, error);
+		atomic_subtract_int(&chan->ch_refs, 1);
 		vmbus_chan_free(chan);
 		return;
 	}
@@ -1368,7 +1420,7 @@ vmbus_chan_msgproc_chrescind(struct vmbu
 
 	note = (const struct vmbus_chanmsg_chrescind *)msg->msg_data;
 	if (note->chm_chanid > VMBUS_CHAN_MAX) {
-		device_printf(sc->vmbus_dev, "invalid rescinded chan%u\n",
+		device_printf(sc->vmbus_dev, "invalid revoked chan%u\n",
 		    note->chm_chanid);
 		return;
 	}
@@ -1403,11 +1455,24 @@ vmbus_chan_msgproc_chrescind(struct vmbu
 		mtx_unlock(&sc->vmbus_prichan_lock);
 	}
 
-	if (bootverbose)
-		vmbus_chan_printf(chan, "chan%u rescinded\n", note->chm_chanid);
+	/*
+	 * 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");
 
-	/* Detach the target channel. */
-	taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_detach_task);
+	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);
+	vmbus_chan_detach(chan);
 }
 
 static int
@@ -1695,3 +1760,30 @@ vmbus_chan_mgmt_tq(const struct vmbus_ch
 
 	return (chan->ch_mgmt_tq);
 }
+
+bool
+vmbus_chan_is_revoked(const struct vmbus_channel *chan)
+{
+
+	if (chan->ch_stflags & VMBUS_CHAN_ST_REVOKED)
+		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);
+}

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_chanvar.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_chanvar.h	Thu Jan  5 03:42:29 2017	(r311358)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_chanvar.h	Thu Jan  5 04:22:03 2017	(r311359)
@@ -33,8 +33,9 @@
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/queue.h>
-#include <sys/taskqueue.h>
 #include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
 
 #include <dev/hyperv/include/hyperv.h>
 #include <dev/hyperv/include/hyperv_busdma.h>
@@ -138,6 +139,11 @@ struct vmbus_channel {
 	struct hyperv_guid		ch_guid_type;
 	struct hyperv_guid		ch_guid_inst;
 
+	struct sx			ch_orphan_lock;
+	struct vmbus_xact_ctx		*ch_orphan_xact;
+
+	int				ch_refs;
+
 	struct sysctl_ctx_list		ch_sysctl_ctx;
 } __aligned(CACHE_LINE_SIZE);
 
@@ -159,10 +165,12 @@ struct vmbus_channel {
 #define VMBUS_CHAN_ST_ONPRIL_SHIFT	1
 #define VMBUS_CHAN_ST_ONSUBL_SHIFT	2
 #define VMBUS_CHAN_ST_ONLIST_SHIFT	3
+#define VMBUS_CHAN_ST_REVOKED_SHIFT	4	/* sticky */
 #define VMBUS_CHAN_ST_OPENED		(1 << VMBUS_CHAN_ST_OPENED_SHIFT)
 #define VMBUS_CHAN_ST_ONPRIL		(1 << VMBUS_CHAN_ST_ONPRIL_SHIFT)
 #define VMBUS_CHAN_ST_ONSUBL		(1 << VMBUS_CHAN_ST_ONSUBL_SHIFT)
 #define VMBUS_CHAN_ST_ONLIST		(1 << VMBUS_CHAN_ST_ONLIST_SHIFT)
+#define VMBUS_CHAN_ST_REVOKED		(1 << VMBUS_CHAN_ST_REVOKED_SHIFT)
 
 struct vmbus_softc;
 struct vmbus_message;

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_xact.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_xact.c	Thu Jan  5 03:42:29 2017	(r311358)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_xact.c	Thu Jan  5 04:22:03 2017	(r311359)
@@ -50,16 +50,18 @@ struct vmbus_xact {
 };
 
 struct vmbus_xact_ctx {
-	uint32_t			xc_flags;
 	size_t				xc_req_size;
 	size_t				xc_resp_size;
 	size_t				xc_priv_size;
 
+	struct mtx			xc_lock;
+	/*
+	 * Protected by xc_lock.
+	 */
+	uint32_t			xc_flags;	/* VMBUS_XACT_CTXF_ */
 	struct vmbus_xact		*xc_free;
-	struct mtx			xc_free_lock;
-
 	struct vmbus_xact		*xc_active;
-	struct mtx			xc_active_lock;
+	struct vmbus_xact		*xc_orphan;
 };
 
 #define VMBUS_XACT_CTXF_DESTROY		0x0001
@@ -71,6 +73,9 @@ static struct vmbus_xact	*vmbus_xact_get
 				    uint32_t);
 const void			*vmbus_xact_wait1(struct vmbus_xact *, size_t *,
 				    bool);
+static void			vmbus_xact_save_resp(struct vmbus_xact *,
+				    const void *, size_t);
+static void			vmbus_xact_ctx_free(struct vmbus_xact_ctx *);
 
 static struct vmbus_xact *
 vmbus_xact_alloc(struct vmbus_xact_ctx *ctx, bus_dma_tag_t parent_dtag)
@@ -110,10 +115,10 @@ vmbus_xact_get1(struct vmbus_xact_ctx *c
 {
 	struct vmbus_xact *xact;
 
-	mtx_lock(&ctx->xc_free_lock);
+	mtx_lock(&ctx->xc_lock);
 
 	while ((ctx->xc_flags & dtor_flag) == 0 && ctx->xc_free == NULL)
-		mtx_sleep(&ctx->xc_free, &ctx->xc_free_lock, 0, "gxact", 0);
+		mtx_sleep(&ctx->xc_free, &ctx->xc_lock, 0, "gxact", 0);
 	if (ctx->xc_flags & dtor_flag) {
 		/* Being destroyed */
 		xact = NULL;
@@ -124,7 +129,7 @@ vmbus_xact_get1(struct vmbus_xact_ctx *c
 		ctx->xc_free = NULL;
 	}
 
-	mtx_unlock(&ctx->xc_free_lock);
+	mtx_unlock(&ctx->xc_lock);
 
 	return (xact);
 }
@@ -135,6 +140,9 @@ vmbus_xact_ctx_create(bus_dma_tag_t dtag
 {
 	struct vmbus_xact_ctx *ctx;
 
+	KASSERT(req_size > 0, ("request size is 0"));
+	KASSERT(resp_size > 0, ("response size is 0"));
+
 	ctx = malloc(sizeof(*ctx), M_DEVBUF, M_WAITOK | M_ZERO);
 	ctx->xc_req_size = req_size;
 	ctx->xc_resp_size = resp_size;
@@ -146,32 +154,51 @@ vmbus_xact_ctx_create(bus_dma_tag_t dtag
 		return (NULL);
 	}
 
-	mtx_init(&ctx->xc_free_lock, "vmbus xact free", NULL, MTX_DEF);
-	mtx_init(&ctx->xc_active_lock, "vmbus xact active", NULL, MTX_DEF);
+	mtx_init(&ctx->xc_lock, "vmbus xact", NULL, MTX_DEF);
 
 	return (ctx);
 }
 
-void
-vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx)
+bool
+vmbus_xact_ctx_orphan(struct vmbus_xact_ctx *ctx)
 {
-	struct vmbus_xact *xact;
-
-	mtx_lock(&ctx->xc_free_lock);
+	mtx_lock(&ctx->xc_lock);
+	if (ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) {
+		mtx_unlock(&ctx->xc_lock);
+		return (false);
+	}
 	ctx->xc_flags |= VMBUS_XACT_CTXF_DESTROY;
-	mtx_unlock(&ctx->xc_free_lock);
+	mtx_unlock(&ctx->xc_lock);
+
 	wakeup(&ctx->xc_free);
+	wakeup(&ctx->xc_active);
 
-	xact = vmbus_xact_get1(ctx, 0);
-	if (xact == NULL)
+	ctx->xc_orphan = vmbus_xact_get1(ctx, 0);
+	if (ctx->xc_orphan == NULL)
 		panic("can't get xact");
+	return (true);
+}
+
+static void
+vmbus_xact_ctx_free(struct vmbus_xact_ctx *ctx)
+{
+	KASSERT(ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY,
+	    ("xact ctx was not orphaned"));
+	KASSERT(ctx->xc_orphan != NULL, ("no orphaned xact"));
 
-	vmbus_xact_free(xact);
-	mtx_destroy(&ctx->xc_free_lock);
-	mtx_destroy(&ctx->xc_active_lock);
+	vmbus_xact_free(ctx->xc_orphan);
+	mtx_destroy(&ctx->xc_lock);
 	free(ctx, M_DEVBUF);
 }
 
+void
+vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx)
+{
+
+	vmbus_xact_ctx_orphan(ctx);
+	vmbus_xact_ctx_free(ctx);
+}
+
 struct vmbus_xact *
 vmbus_xact_get(struct vmbus_xact_ctx *ctx, size_t req_len)
 {
@@ -196,10 +223,10 @@ vmbus_xact_put(struct vmbus_xact *xact)
 	KASSERT(ctx->xc_active == NULL, ("pending active xact"));
 	xact->x_resp = NULL;
 
-	mtx_lock(&ctx->xc_free_lock);
+	mtx_lock(&ctx->xc_lock);
 	KASSERT(ctx->xc_free == NULL, ("has free xact"));
 	ctx->xc_free = xact;
-	mtx_unlock(&ctx->xc_free_lock);
+	mtx_unlock(&ctx->xc_lock);
 	wakeup(&ctx->xc_free);
 }
 
@@ -233,10 +260,10 @@ vmbus_xact_activate(struct vmbus_xact *x
 
 	KASSERT(xact->x_resp == NULL, ("xact has pending response"));
 
-	mtx_lock(&ctx->xc_active_lock);
+	mtx_lock(&ctx->xc_lock);
 	KASSERT(ctx->xc_active == NULL, ("pending active xact"));
 	ctx->xc_active = xact;
-	mtx_unlock(&ctx->xc_active_lock);
+	mtx_unlock(&ctx->xc_lock);
 }
 
 void
@@ -244,10 +271,10 @@ vmbus_xact_deactivate(struct vmbus_xact 
 {
 	struct vmbus_xact_ctx *ctx = xact->x_ctx;
 
-	mtx_lock(&ctx->xc_active_lock);
+	mtx_lock(&ctx->xc_lock);
 	KASSERT(ctx->xc_active == xact, ("xact mismatch"));
 	ctx->xc_active = NULL;
-	mtx_unlock(&ctx->xc_active_lock);
+	mtx_unlock(&ctx->xc_lock);
 }
 
 const void *
@@ -257,25 +284,40 @@ vmbus_xact_wait1(struct vmbus_xact *xact
 	struct vmbus_xact_ctx *ctx = xact->x_ctx;
 	const void *resp;
 
-	mtx_lock(&ctx->xc_active_lock);
+	mtx_lock(&ctx->xc_lock);
 
 	KASSERT(ctx->xc_active == xact, ("xact mismatch"));
-	while (xact->x_resp == NULL) {
+	while (xact->x_resp == NULL &&
+	    (ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) == 0) {
 		if (can_sleep) {
-			mtx_sleep(&ctx->xc_active, &ctx->xc_active_lock, 0,
+			mtx_sleep(&ctx->xc_active, &ctx->xc_lock, 0,
 			    "wxact", 0);
 		} else {
-			mtx_unlock(&ctx->xc_active_lock);
+			mtx_unlock(&ctx->xc_lock);
 			DELAY(1000);
-			mtx_lock(&ctx->xc_active_lock);
+			mtx_lock(&ctx->xc_lock);
 		}
 	}
+	KASSERT(ctx->xc_active == xact, ("xact trashed"));
+
+	if ((ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY) && xact->x_resp == NULL) {
+		uint8_t b = 0;
+
+		/*
+		 * Orphaned and no response was received yet; fake up
+		 * an one byte response.
+		 */
+		printf("vmbus: xact ctx was orphaned w/ pending xact\n");
+		vmbus_xact_save_resp(ctx->xc_active, &b, sizeof(b));
+	}
+	KASSERT(xact->x_resp != NULL, ("no response"));
+
 	ctx->xc_active = NULL;
 
 	resp = xact->x_resp;
 	*resp_len = xact->x_resp_len;
 
-	mtx_unlock(&ctx->xc_active_lock);
+	mtx_unlock(&ctx->xc_lock);
 
 	return (resp);
 }
@@ -300,7 +342,7 @@ vmbus_xact_save_resp(struct vmbus_xact *
 	struct vmbus_xact_ctx *ctx = xact->x_ctx;
 	size_t cplen = dlen;
 
-	mtx_assert(&ctx->xc_active_lock, MA_OWNED);
+	mtx_assert(&ctx->xc_lock, MA_OWNED);
 
 	if (cplen > ctx->xc_resp_size) {
 		printf("vmbus: xact response truncated %zu -> %zu\n",
@@ -318,19 +360,47 @@ void
 vmbus_xact_wakeup(struct vmbus_xact *xact, const void *data, size_t dlen)
 {
 	struct vmbus_xact_ctx *ctx = xact->x_ctx;
+	int do_wakeup = 0;
 
-	mtx_lock(&ctx->xc_active_lock);
-	vmbus_xact_save_resp(xact, data, dlen);
-	mtx_unlock(&ctx->xc_active_lock);
-	wakeup(&ctx->xc_active);
+	mtx_lock(&ctx->xc_lock);
+	/*
+	 * NOTE:
+	 * xc_active could be NULL, if the ctx has been orphaned.
+	 */
+	if (ctx->xc_active != NULL) {
+		vmbus_xact_save_resp(xact, data, dlen);
+		do_wakeup = 1;
+	} else {
+		KASSERT(ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY,
+		    ("no active xact pending"));
+		printf("vmbus: drop xact response\n");
+	}
+	mtx_unlock(&ctx->xc_lock);
+
+	if (do_wakeup)
+		wakeup(&ctx->xc_active);
 }
 
 void
 vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx, const void *data, size_t dlen)
 {
-	mtx_lock(&ctx->xc_active_lock);
-	KASSERT(ctx->xc_active != NULL, ("no pending xact"));
-	vmbus_xact_save_resp(ctx->xc_active, data, dlen);
-	mtx_unlock(&ctx->xc_active_lock);
-	wakeup(&ctx->xc_active);
+	int do_wakeup = 0;
+
+	mtx_lock(&ctx->xc_lock);
+	/*
+	 * NOTE:
+	 * xc_active could be NULL, if the ctx has been orphaned.
+	 */
+	if (ctx->xc_active != NULL) {
+		vmbus_xact_save_resp(ctx->xc_active, data, dlen);
+		do_wakeup = 1;
+	} else {
+		KASSERT(ctx->xc_flags & VMBUS_XACT_CTXF_DESTROY,
+		    ("no active xact pending"));
+		printf("vmbus: drop xact response\n");
+	}
+	mtx_unlock(&ctx->xc_lock);
+
+	if (do_wakeup)
+		wakeup(&ctx->xc_active);
 }



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