diff options
Diffstat (limited to 'lib/libvfio-user.c')
-rw-r--r-- | lib/libvfio-user.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 25b58e0..a56d34c 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -335,7 +335,18 @@ handle_region_access(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) ret = region_access(vfu_ctx, in_ra->region, buf, in_ra->count, in_ra->offset, msg->hdr.cmd == VFIO_USER_REGION_WRITE); - + if (ret == -1 && in_ra->region == VFU_PCI_DEV_MIGR_REGION_IDX + && errno == EBUSY && (vfu_ctx->flags & LIBVFIO_USER_FLAG_ATTACH_NB)) { + /* + * We don't support async behavior for the non-blocking mode simply + * because we don't have a use case yet, the only user of migration + * is SPDK and it operates in non-blocking mode. We don't know the + * implications of enabling this in blocking mode as we haven't looked + * at the details. + */ + vfu_ctx->migr_trans_pending = true; + return 0; + } if (ret != in_ra->count) { vfu_log(vfu_ctx, LOG_ERR, "failed to %s %#lx-%#lx: %m", msg->hdr.cmd == VFIO_USER_REGION_WRITE ? "write" : "read", @@ -1209,6 +1220,29 @@ exec_command(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) return ret; } +static int +do_reply(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, int reply_errno) +{ + assert(vfu_ctx != NULL); + assert(msg != NULL); + + int ret = vfu_ctx->tran->reply(vfu_ctx, msg, reply_errno); + + if (ret < 0) { + vfu_log(vfu_ctx, LOG_ERR, "failed to reply: %m"); + + if (errno == ECONNRESET) { + vfu_reset_ctx(vfu_ctx, "reset"); + errno = ENOTCONN; + } else if (errno == ENOMSG) { + vfu_reset_ctx(vfu_ctx, "closed"); + errno = ENOTCONN; + } + } + + return ret; +} + /* * Handle requests over the vfio-user socket. This can return immediately if we * are non-blocking, and there is no request from the client ready to read from @@ -1257,25 +1291,19 @@ process_request(vfu_ctx_t *vfu_ctx) } out: + if (vfu_ctx->migr_trans_pending) { + assert(ret == 0); + vfu_ctx->migr_trans_msg = msg; + /* NB the message is freed in vfu_migr_done */ + return 0; + } if (msg->hdr.flags.no_reply) { /* * A failed client request is not a failure of process_request() itself. */ ret = 0; } else { - ret = vfu_ctx->tran->reply(vfu_ctx, msg, ret == 0 ? 0 : errno); - - if (ret < 0) { - vfu_log(vfu_ctx, LOG_ERR, "failed to reply: %m"); - - if (errno == ECONNRESET) { - vfu_reset_ctx(vfu_ctx, "reset"); - errno = ENOTCONN; - } else if (errno == ENOMSG) { - vfu_reset_ctx(vfu_ctx, "closed"); - errno = ENOTCONN; - } - } + ret = do_reply(vfu_ctx, msg, ret == 0 ? 0 : errno); } free_msg(vfu_ctx, msg); @@ -1376,6 +1404,9 @@ vfu_run_ctx(vfu_ctx_t *vfu_ctx) blocking = !(vfu_ctx->flags & LIBVFIO_USER_FLAG_ATTACH_NB); do { + if (vfu_ctx->migr_trans_pending) { + return ERROR_INT(EBUSY); + } err = process_request(vfu_ctx); if (err == 0) { @@ -1928,12 +1959,14 @@ vfu_dma_transfer(vfu_ctx_t *vfu_ctx, enum vfio_user_command cmd, EXPORT int vfu_dma_read(vfu_ctx_t *vfu_ctx, dma_sg_t *sg, void *data) { + assert(!vfu_ctx->migr_trans_pending); return vfu_dma_transfer(vfu_ctx, VFIO_USER_DMA_READ, sg, data); } EXPORT int vfu_dma_write(vfu_ctx_t *vfu_ctx, dma_sg_t *sg, void *data) { + assert(!vfu_ctx->migr_trans_pending); return vfu_dma_transfer(vfu_ctx, VFIO_USER_DMA_WRITE, sg, data); } @@ -1943,4 +1976,19 @@ vfu_sg_is_mappable(vfu_ctx_t *vfu_ctx, dma_sg_t *sg) return dma_sg_is_mappable(vfu_ctx->dma, sg); } +EXPORT void +vfu_migr_done(vfu_ctx_t *vfu_ctx, int reply_errno) +{ + assert(vfu_ctx != NULL); + assert(vfu_ctx->migr_trans_pending); + + if (!vfu_ctx->migr_trans_msg->hdr.flags.no_reply) { + do_reply(vfu_ctx, vfu_ctx->migr_trans_msg, reply_errno); + } + free_msg(vfu_ctx, vfu_ctx->migr_trans_msg); + vfu_ctx->migr_trans_msg = NULL; + + vfu_ctx->migr_trans_pending = false; +} + /* ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */ |