aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThanos Makatos <thanos.makatos@nutanix.com>2022-03-07 09:42:05 +0000
committerGitHub <noreply@github.com>2022-03-07 09:42:05 +0000
commita8d452e8e384be847377ab41a7ee19d4da71fde3 (patch)
tree53bf43c651e6f7af7b3add7034d197c6f6276dc6
parent6bb0c5c7747499a0463c78a97591a64d1324aba7 (diff)
downloadlibvfio-user-a8d452e8e384be847377ab41a7ee19d4da71fde3.zip
libvfio-user-a8d452e8e384be847377ab41a7ee19d4da71fde3.tar.gz
libvfio-user-a8d452e8e384be847377ab41a7ee19d4da71fde3.tar.bz2
check for allowed operations in quiesce state (#647)
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com> Reviewed-by: John Levon <john.levon@nutanix.com>
-rw-r--r--lib/dma.c4
-rw-r--r--lib/libvfio-user.c41
-rw-r--r--lib/migration.c4
-rw-r--r--lib/private.h11
4 files changed, 60 insertions, 0 deletions
diff --git a/lib/dma.c b/lib/dma.c
index 26c5758..3eb23f9 100644
--- a/lib/dma.c
+++ b/lib/dma.c
@@ -167,7 +167,9 @@ MOCK_DEFINE(dma_controller_remove_region)(dma_controller_t *dma,
}
if (dma_unregister != NULL) {
+ dma->vfu_ctx->in_cb = CB_DMA_UNREGISTER;
dma_unregister(data, &region->info);
+ dma->vfu_ctx->in_cb = CB_NONE;
}
assert(region->refcnt == 0);
@@ -203,7 +205,9 @@ dma_controller_remove_all_regions(dma_controller_t *dma,
region->info.mapping.iov_base, iov_end(&region->info.mapping));
if (dma_unregister != NULL) {
+ dma->vfu_ctx->in_cb = CB_DMA_UNREGISTER;
dma_unregister(data, &region->info);
+ dma->vfu_ctx->in_cb = CB_NONE;
}
if (region->info.vaddr != NULL) {
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c
index d8e11d0..aee2f8e 100644
--- a/lib/libvfio-user.c
+++ b/lib/libvfio-user.c
@@ -712,7 +712,10 @@ handle_dma_map(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg,
}
if (vfu_ctx->dma_register != NULL) {
+ vfu_ctx->in_cb = CB_DMA_REGISTER;
vfu_ctx->dma_register(vfu_ctx, &vfu_ctx->dma->regions[ret].info);
+ vfu_ctx->in_cb = CB_NONE;
+
}
return 0;
}
@@ -848,7 +851,9 @@ do_device_reset(vfu_ctx_t *vfu_ctx, vfu_reset_type_t reason)
int ret;
if (vfu_ctx->reset != NULL) {
+ vfu_ctx->in_cb = CB_RESET;
ret = vfu_ctx->reset(vfu_ctx, reason);
+ vfu_ctx->in_cb = CB_NONE;
if (ret < 0) {
return ret;
}
@@ -1369,7 +1374,9 @@ get_request(vfu_ctx_t *vfu_ctx, vfu_msg_t **msgp)
if (command_needs_quiesce(vfu_ctx, msg)) {
vfu_log(vfu_ctx, LOG_DEBUG, "quiescing device");
+ vfu_ctx->in_cb = CB_QUIESCE;
ret = vfu_ctx->quiesce(vfu_ctx);
+ vfu_ctx->in_cb = CB_NONE;
if (ret < 0) {
if (errno != EBUSY) {
vfu_log(vfu_ctx, LOG_DEBUG, "device failed to quiesce: %m");
@@ -1384,6 +1391,7 @@ get_request(vfu_ctx_t *vfu_ctx, vfu_msg_t **msgp)
}
vfu_log(vfu_ctx, LOG_DEBUG, "device quiesced immediately");
+ vfu_ctx->quiesced = true;
}
*msgp = msg;
@@ -1429,6 +1437,15 @@ vfu_run_ctx(vfu_ctx_t *vfu_ctx)
err = handle_request(vfu_ctx, msg);
free_msg(vfu_ctx, msg);
reqs_processed++;
+ /*
+ * get_request might call the quiesce callback which might
+ * immediately quiesce the device, vfu_device_quiesced won't
+ * be called at all.
+ */
+ if (vfu_ctx->quiesced) {
+ vfu_log(vfu_ctx, LOG_DEBUG, "device unquiesced");
+ vfu_ctx->quiesced = false;
+ }
} else {
/*
* If there was no request to read, or we already handled the
@@ -1563,7 +1580,9 @@ vfu_reset_ctx(vfu_ctx_t *vfu_ctx, int reason)
if (vfu_ctx->quiesce != NULL
&& vfu_ctx->pending.state == VFU_CTX_PENDING_NONE) {
+ vfu_ctx->in_cb = CB_QUIESCE;
int ret = vfu_ctx->quiesce(vfu_ctx);
+ vfu_ctx->in_cb = CB_NONE;
if (ret < 0) {
if (errno == EBUSY) {
vfu_ctx->pending.state = VFU_CTX_PENDING_CTX_RESET;
@@ -1956,6 +1975,17 @@ vfu_setup_device_migration_callbacks(vfu_ctx_t *vfu_ctx,
return 0;
}
+static void
+quiesce_check_allowed(vfu_ctx_t *vfu_ctx)
+{
+ if (!(vfu_ctx->in_cb != CB_NONE || vfu_ctx->quiesce == NULL || !vfu_ctx->quiesced)) {
+ vfu_log(vfu_ctx, LOG_ERR, "illegal function in quiesced state");
+#ifdef DEBUG
+ abort();
+#endif
+ }
+}
+
EXPORT int
vfu_addr_to_sg(vfu_ctx_t *vfu_ctx, vfu_dma_addr_t dma_addr,
size_t len, dma_sg_t *sg, int max_sg, int prot)
@@ -1966,6 +1996,8 @@ vfu_addr_to_sg(vfu_ctx_t *vfu_ctx, vfu_dma_addr_t dma_addr,
return ERROR_INT(EINVAL);
}
+ quiesce_check_allowed(vfu_ctx);
+
return dma_addr_to_sg(vfu_ctx->dma, dma_addr, len, sg, max_sg, prot);
}
@@ -1979,6 +2011,8 @@ vfu_map_sg(vfu_ctx_t *vfu_ctx, dma_sg_t *sg, struct iovec *iov, int cnt,
return ERROR_INT(EINVAL);
}
+ quiesce_check_allowed(vfu_ctx);
+
ret = dma_map_sg(vfu_ctx->dma, sg, iov, cnt);
if (ret < 0) {
return -1;
@@ -1993,6 +2027,9 @@ vfu_unmap_sg(vfu_ctx_t *vfu_ctx, dma_sg_t *sg, struct iovec *iov, int cnt)
if (unlikely(vfu_ctx->dma_unregister == NULL)) {
return;
}
+
+ quiesce_check_allowed(vfu_ctx);
+
return dma_unmap_sg(vfu_ctx->dma, sg, iov, cnt);
}
@@ -2125,6 +2162,7 @@ vfu_device_quiesced(vfu_ctx_t *vfu_ctx, int quiesce_errno)
}
vfu_log(vfu_ctx, LOG_DEBUG, "device quiesced with error=%d", quiesce_errno);
+ vfu_ctx->quiesced = true;
if (quiesce_errno == 0) {
switch (vfu_ctx->pending.state) {
@@ -2147,6 +2185,9 @@ vfu_device_quiesced(vfu_ctx_t *vfu_ctx, int quiesce_errno)
vfu_ctx->pending.msg = NULL;
vfu_ctx->pending.state = VFU_CTX_PENDING_NONE;
+ vfu_log(vfu_ctx, LOG_DEBUG, "device unquiesced");
+ vfu_ctx->quiesced = false;
+
return ret;
}
diff --git a/lib/migration.c b/lib/migration.c
index 64ef4a7..fc5bb39 100644
--- a/lib/migration.c
+++ b/lib/migration.c
@@ -155,8 +155,12 @@ MOCK_DEFINE(migr_trans_to_valid_state)(vfu_ctx_t *vfu_ctx, struct migration *mig
{
if (notify) {
int ret;
+ assert(!vfu_ctx->in_cb);
+ vfu_ctx->in_cb = CB_MIGR_STATE;
ret = state_trans_notify(vfu_ctx, migr->callbacks.transition,
device_state);
+ vfu_ctx->in_cb = CB_NONE;
+
if (ret != 0) {
return ret;
}
diff --git a/lib/private.h b/lib/private.h
index db2cbbf..21c6dbd 100644
--- a/lib/private.h
+++ b/lib/private.h
@@ -164,6 +164,15 @@ struct vfu_ctx_pending_info {
uint32_t migr_dev_state;
};
+enum cb_type {
+ CB_NONE,
+ CB_DMA_REGISTER,
+ CB_DMA_UNREGISTER,
+ CB_RESET,
+ CB_QUIESCE,
+ CB_MIGR_STATE
+};
+
struct vfu_ctx {
void *pvt;
struct dma_controller *dma;
@@ -187,6 +196,8 @@ struct vfu_ctx {
size_t client_max_data_xfer_size;
struct vfu_ctx_pending_info pending;
+ bool quiesced;
+ enum cb_type in_cb;
struct migration *migration;