aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorSepherosa Ziehau <sephe@FreeBSD.org>2016-11-24 04:58:13 +0000
committerSepherosa Ziehau <sephe@FreeBSD.org>2016-11-24 04:58:13 +0000
commit494ec41ae299d023d86739b18a1778fd4f52feed (patch)
tree5da4d4d99628d1936e119658ebdcb02b32ad2304 /sys/dev
parent49ba3f32c8f48e8e1427f7858f544f435ea5465b (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/hyperv/include/vmbus_xact.h2
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_xact.c97
2 files changed, 86 insertions, 13 deletions
diff --git a/sys/dev/hyperv/include/vmbus_xact.h b/sys/dev/hyperv/include/vmbus_xact.h
index bfe4b88e920b..280c5fef5a2d 100644
--- a/sys/dev/hyperv/include/vmbus_xact.h
+++ b/sys/dev/hyperv/include/vmbus_xact.h
@@ -39,6 +39,8 @@ struct vmbus_xact_ctx *vmbus_xact_ctx_create(bus_dma_tag_t dtag,
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);
diff --git a/sys/dev/hyperv/vmbus/vmbus_xact.c b/sys/dev/hyperv/vmbus/vmbus_xact.c
index 944d92894c75..c0219e837263 100644
--- a/sys/dev/hyperv/vmbus/vmbus_xact.c
+++ b/sys/dev/hyperv/vmbus/vmbus_xact.c
@@ -61,6 +61,7 @@ struct vmbus_xact_ctx {
uint32_t xc_flags; /* VMBUS_XACT_CTXF_ */
struct vmbus_xact *xc_free;
struct vmbus_xact *xc_active;
+ struct vmbus_xact *xc_orphan;
};
#define VMBUS_XACT_CTXF_DESTROY 0x0001
@@ -72,6 +73,9 @@ static struct vmbus_xact *vmbus_xact_get1(struct vmbus_xact_ctx *,
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)
@@ -136,6 +140,9 @@ vmbus_xact_ctx_create(bus_dma_tag_t dtag, size_t req_size, size_t resp_size,
{
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;
@@ -152,25 +159,46 @@ vmbus_xact_ctx_create(bus_dma_tag_t dtag, size_t req_size, size_t resp_size,
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_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_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);
+}
- vmbus_xact_free(xact);
+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(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)
{
@@ -259,7 +287,8 @@ vmbus_xact_wait1(struct vmbus_xact *xact, size_t *resp_len,
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_lock, 0,
"wxact", 0);
@@ -269,6 +298,20 @@ vmbus_xact_wait1(struct vmbus_xact *xact, size_t *resp_len,
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;
@@ -317,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_lock);
- vmbus_xact_save_resp(xact, data, dlen);
+ /*
+ * 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);
- wakeup(&ctx->xc_active);
+
+ if (do_wakeup)
+ wakeup(&ctx->xc_active);
}
void
vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx, const void *data, size_t dlen)
{
+ int do_wakeup = 0;
+
mtx_lock(&ctx->xc_lock);
- KASSERT(ctx->xc_active != NULL, ("no pending xact"));
- vmbus_xact_save_resp(ctx->xc_active, data, dlen);
+ /*
+ * 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);
- wakeup(&ctx->xc_active);
+
+ if (do_wakeup)
+ wakeup(&ctx->xc_active);
}