diff options
author | Thanos Makatos <thanos.makatos@nutanix.com> | 2020-11-26 05:37:02 -0500 |
---|---|---|
committer | Thanos <tmakatos@gmail.com> | 2020-11-27 09:36:12 +0000 |
commit | 24cacccd92a0da049af83d4da35bd3bcebf236ae (patch) | |
tree | 9fd35a360f5ddcc08476fd8493f48d789590f43f /lib | |
parent | 4235d834cfd090c7d33352adda8762679a132347 (diff) | |
download | libvfio-user-24cacccd92a0da049af83d4da35bd3bcebf236ae.zip libvfio-user-24cacccd92a0da049af83d4da35bd3bcebf236ae.tar.gz libvfio-user-24cacccd92a0da049af83d4da35bd3bcebf236ae.tar.bz2 |
allow DMA regions without file descriptor
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma.c | 46 | ||||
-rw-r--r-- | lib/muser_ctx.c | 64 |
2 files changed, 58 insertions, 52 deletions
@@ -61,9 +61,8 @@ fds_are_same_file(int fd1, int fd2) { struct stat st1, st2; - if (fd1 == -1 || fd2 == -1) { - errno = EINVAL; - return -1; + if (fd1 == fd2) { + return true; } return (fstat(fd1, &st1) == 0 && fstat(fd2, &st2) == 0 && @@ -210,15 +209,10 @@ dma_controller_add_region(dma_controller_t *dma, { int idx; dma_memory_region_t *region; - int page_size; + int page_size = 0; assert(dma != NULL); - if (fd == -1) { - errno = EINVAL; - return -1; - } - for (idx = 0; idx < dma->nregions; idx++) { region = &dma->regions[idx]; @@ -267,10 +261,12 @@ dma_controller_add_region(dma_controller_t *dma, idx = dma->nregions; region = &dma->regions[idx]; - page_size = fd_get_blocksize(fd); - if (page_size < 0) { - lm_log(dma->lm_ctx, LM_ERR, "bad page size %d\n", page_size); - goto err; + if (fd != -1) { + page_size = fd_get_blocksize(fd); + if (page_size < 0) { + lm_log(dma->lm_ctx, LM_ERR, "bad page size %d\n", page_size); + goto err; + } } page_size = MAX(page_size, getpagesize()); @@ -281,19 +277,21 @@ dma_controller_add_region(dma_controller_t *dma, region->fd = fd; region->refcnt = 0; - region->virt_addr = dma_map_region(region, PROT_READ | PROT_WRITE, - 0, region->size); - if (region->virt_addr == MAP_FAILED) { - lm_log(dma->lm_ctx, LM_ERR, - "failed to memory map DMA region %#lx-%#lx: %s\n", - dma_addr, dma_addr + size, strerror(errno)); - if (region->fd != -1) { - if (close(region->fd) == -1) { - lm_log(dma->lm_ctx, LM_DBG, "failed to close fd %d: %m\n", - region->fd); + if (fd != -1) { + region->virt_addr = dma_map_region(region, PROT_READ | PROT_WRITE, + 0, region->size); + if (region->virt_addr == MAP_FAILED) { + lm_log(dma->lm_ctx, LM_ERR, + "failed to memory map DMA region %#lx-%#lx: %s\n", + dma_addr, dma_addr + size, strerror(errno)); + if (region->fd != -1) { + if (close(region->fd) == -1) { + lm_log(dma->lm_ctx, LM_DBG, "failed to close fd %d: %m\n", + region->fd); + } } + goto err; } - goto err; } dma->nregions++; diff --git a/lib/muser_ctx.c b/lib/muser_ctx.c index e1b18b1..e00a55a 100644 --- a/lib/muser_ctx.c +++ b/lib/muser_ctx.c @@ -499,70 +499,78 @@ handle_device_get_info(lm_ctx_t *lm_ctx, uint32_t size, return 0; } +/* + * Handles a DMA map/unmap request. + * + * @lm_ctx: LM context + * @size: size, in bytes, of the memory pointed to be @dma_regions + * @map: whether this is a DMA map operation + * @fds: array of file descriptors. It's length must equal the number of DMA + regions, irrespectively if @nr_fds is 0. + * @nr_fds: size of above array. It must be either 0 or exactly match + * the number of DMA regions in @dma_regions. + * @dma_regions: memory that contains the DMA regions to be mapped/unmapped + * + * @returns 0 on success, -errno on failure. + */ int handle_dma_map_or_unmap(lm_ctx_t *lm_ctx, uint32_t size, bool map, int *fds, int nr_fds, struct vfio_user_dma_region *dma_regions) { int nr_dma_regions; - int fdi = 0; int ret, i; assert(lm_ctx != NULL); + assert(fds != NULL); + + if (lm_ctx->dma == NULL) { + return 0; + } if (size % sizeof(struct vfio_user_dma_region) != 0) { lm_log(lm_ctx, LM_ERR, "bad size of DMA regions %d", size); return -EINVAL; } - if (lm_ctx->dma == NULL) { - return 0; - } - nr_dma_regions = (int)(size / sizeof(struct vfio_user_dma_region)); + if (map && nr_fds > 0 && nr_dma_regions != nr_fds) { + lm_log(lm_ctx, LM_ERR, "expected %d fds but got %d instead", + nr_dma_regions, nr_fds); + return -EINVAL; + } for (i = 0; i < nr_dma_regions; i++) { if (map) { - int fd; - - /* - * FIXME: need a dma controller that allows non-fd region. - */ - if (dma_regions[i].flags != VFIO_USER_F_DMA_REGION_MAPPABLE) { - lm_log(lm_ctx, LM_INF, - "FIXME: ignored non-mappable DMA region " - "%#lx-%#lx offset=%#lx", - dma_regions[i].addr, - dma_regions[i].addr + dma_regions[i].size - 1, - dma_regions[i].offset); - continue; - } - - if (fdi >= nr_fds) { - lm_log(lm_ctx, LM_ERR, "missing fd for mappable region %d", i); - return -EINVAL; + if (dma_regions[i].flags == VFIO_USER_F_DMA_REGION_MAPPABLE) { + if (nr_fds == 0) { + return -EINVAL; + } + } else { + if (nr_fds != 0) { + return -EINVAL; + } + fds[i] = -1; } - fd = fds[fdi++]; - ret = dma_controller_add_region(lm_ctx->dma, dma_regions[i].addr, dma_regions[i].size, - fd, + fds[i], dma_regions[i].offset); if (ret < 0) { lm_log(lm_ctx, LM_INF, "failed to add DMA region %#lx-%#lx offset=%#lx fd=%d: %s", dma_regions[i].addr, dma_regions[i].addr + dma_regions[i].size - 1, - dma_regions[i].offset, fd, + dma_regions[i].offset, fds[i], strerror(-ret)); } else { lm_log(lm_ctx, LM_DBG, "added DMA region %#lx-%#lx offset=%#lx fd=%d", dma_regions[i].addr, dma_regions[i].addr + dma_regions[i].size - 1, - dma_regions[i].offset, fd); + dma_regions[i].offset, fds[i]); } } else { ret = dma_controller_remove_region(lm_ctx->dma, |