diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma.c | 4 | ||||
-rw-r--r-- | lib/libvfio-user.c | 41 | ||||
-rw-r--r-- | lib/migration.c | 4 | ||||
-rw-r--r-- | lib/private.h | 11 |
4 files changed, 60 insertions, 0 deletions
@@ -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, ®ion->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(®ion->info.mapping)); if (dma_unregister != NULL) { + dma->vfu_ctx->in_cb = CB_DMA_UNREGISTER; dma_unregister(data, ®ion->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; |