diff options
author | Thanos Makatos <thanos.makatos@nutanix.com> | 2021-05-26 09:45:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-26 09:45:05 +0100 |
commit | af573e10982f8b240927674d9be72d99aa39dd81 (patch) | |
tree | eba36998c42250260ccc3fb884eeacb61f16fc76 /lib/libvfio-user.c | |
parent | bd32c19beaac4007207b682e2d9e55ddeea5a5f6 (diff) | |
download | libvfio-user-af573e10982f8b240927674d9be72d99aa39dd81.zip libvfio-user-af573e10982f8b240927674d9be72d99aa39dd81.tar.gz libvfio-user-af573e10982f8b240927674d9be72d99aa39dd81.tar.bz2 |
don't support multiple DMA regions per map/unmap (#520)
We're dropping this behavior from the spec.
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: John Levon <john.levon@nutanix.com>
Diffstat (limited to 'lib/libvfio-user.c')
-rw-r--r-- | lib/libvfio-user.c | 146 |
1 files changed, 79 insertions, 67 deletions
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 138a27b..ae044e8 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -467,90 +467,95 @@ consume_fd(int *fds, size_t nr_fds, size_t index) } int -handle_dma_map_or_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) +handle_dma_map(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, + struct vfio_user_dma_region *region) { - struct vfio_user_dma_region *dma_regions = msg->in_data; - bool is_map = (msg->hdr.cmd == VFIO_USER_DMA_MAP); - size_t nr_dma_regions; - size_t fdi; - size_t i; + char rstr[1024]; + int fd = -1; int ret; assert(vfu_ctx != NULL); + assert(msg != NULL); + assert(region != NULL); - if (msg->in_size % sizeof(struct vfio_user_dma_region) != 0) { - vfu_log(vfu_ctx, LOG_ERR, "bad size of DMA regions %zu", msg->in_size); + if (msg->in_size != sizeof(*region)) { + vfu_log(vfu_ctx, LOG_ERR, "bad size of DMA map region %zu", + msg->in_size); return ERROR_INT(EINVAL); } - if (vfu_ctx->dma == NULL) { - return 0; - } + snprintf(rstr, sizeof(rstr), + "[%#lx, %#lx) offset=%#lx prot=%#x flags=%#x", + region->addr, region->addr + region->size, region->offset, + region->prot, region->flags); - nr_dma_regions = msg->in_size / sizeof(struct vfio_user_dma_region); - if (nr_dma_regions == 0) { - return 0; + vfu_log(vfu_ctx, LOG_DEBUG, "adding DMA region %s", rstr); + + if (region->flags == VFIO_USER_F_DMA_REGION_MAPPABLE) { + fd = consume_fd(msg->in_fds, msg->nr_in_fds, 0); + if (fd < 0) { + vfu_log(vfu_ctx, LOG_ERR, + "failed to add DMA region %s: mappable but fd not provided", + rstr); + return -1; + } } - for (i = 0, fdi = 0; i < nr_dma_regions; i++) { - struct vfio_user_dma_region *region = &dma_regions[i]; - char rstr[1024]; + ret = dma_controller_add_region(vfu_ctx->dma, (void *)region->addr, + region->size, fd, region->offset, + region->prot); + if (ret < 0) { + ret = errno; + vfu_log(vfu_ctx, LOG_ERR, "failed to add DMA region %s: %m", rstr); + if (fd != -1) { + close(fd); + } + return ERROR_INT(ret); + } - snprintf(rstr, sizeof(rstr), "[%#lx, %#lx) offset=%#lx " - "prot=%#x flags=%#x", region->addr, region->addr + region->size, - region->offset, region->prot, region->flags); + if (vfu_ctx->dma_register != NULL) { + vfu_ctx->dma_register(vfu_ctx, &vfu_ctx->dma->regions[ret].info); + } + return 0; +} - vfu_log(vfu_ctx, LOG_DEBUG, "%s DMA region %s", - is_map ? "adding" : "removing", rstr); +int +handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, + struct vfio_user_dma_region *region) +{ + int ret; + char rstr[1024]; - if (is_map) { - int fd = -1; - if (region->flags == VFIO_USER_F_DMA_REGION_MAPPABLE) { - fd = consume_fd(msg->in_fds, msg->nr_in_fds, fdi++); - if (fd < 0) { - vfu_log(vfu_ctx, LOG_ERR, "failed to add DMA region %s: " - "mappable but fd not provided", rstr); - return -1; - } - } + assert(vfu_ctx != NULL); + assert(msg != NULL); + assert(region != NULL); - ret = dma_controller_add_region(vfu_ctx->dma, (void *)region->addr, - region->size, fd, region->offset, - region->prot); - if (ret < 0) { - ret = errno; - vfu_log(vfu_ctx, LOG_ERR, "failed to add DMA region %s: %m", - rstr); - if (fd != -1) { - close(fd); - } - return ERROR_INT(ret); - } + if (msg->in_size != sizeof(*region)) { + vfu_log(vfu_ctx, LOG_ERR, "bad size of DMA unmap region %zu", + msg->in_size); + return ERROR_INT(EINVAL); + } - if (vfu_ctx->dma_register != NULL) { - vfu_ctx->dma_register(vfu_ctx, - &vfu_ctx->dma->regions[ret].info); - } + snprintf(rstr, sizeof(rstr), "[%#lx, %#lx) offset=%#lx " + "prot=%#x flags=%#x", region->addr, region->addr + region->size, + region->offset, region->prot, region->flags); - ret = 0; - } else { + vfu_log(vfu_ctx, LOG_DEBUG, "removing DMA region %s", rstr); - if (region->flags != 0) { - vfu_log(vfu_ctx, LOG_ERR, "bad flags=%#x", region->flags); - return ERROR_INT(ENOTSUP); - } - ret = dma_controller_remove_region(vfu_ctx->dma, - (void *)region->addr, - region->size, - vfu_ctx->dma_unregister, - vfu_ctx); - if (ret < 0) { - ret = errno; - vfu_log(vfu_ctx, LOG_ERR, "failed to remove DMA region %s: %m", - rstr); - return ERROR_INT(ret); - } - } + if (region->flags != 0) { + vfu_log(vfu_ctx, LOG_ERR, "bad flags=%#x", region->flags); + return ERROR_INT(ENOTSUP); + } + ret = dma_controller_remove_region(vfu_ctx->dma, + (void *)region->addr, + region->size, + vfu_ctx->dma_unregister, + vfu_ctx); + if (ret < 0) { + ret = errno; + vfu_log(vfu_ctx, LOG_WARNING, + "failed to remove DMA region %s: %m", rstr); + return ERROR_INT(ret); } return ret; } @@ -861,8 +866,15 @@ MOCK_DEFINE(exec_command)(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) switch (msg->hdr.cmd) { case VFIO_USER_DMA_MAP: + if (vfu_ctx->dma != NULL) { + ret = handle_dma_map(vfu_ctx, msg, msg->in_data); + } + break; + case VFIO_USER_DMA_UNMAP: - ret = handle_dma_map_or_unmap(vfu_ctx, msg); + if (vfu_ctx->dma != NULL) { + ret = handle_dma_unmap(vfu_ctx, msg, msg->in_data); + } break; case VFIO_USER_DEVICE_GET_INFO: |