aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorThanos Makatos <thanos.makatos@nutanix.com>2020-11-26 05:37:02 -0500
committerThanos <tmakatos@gmail.com>2020-11-27 09:36:12 +0000
commit24cacccd92a0da049af83d4da35bd3bcebf236ae (patch)
tree9fd35a360f5ddcc08476fd8493f48d789590f43f /lib
parent4235d834cfd090c7d33352adda8762679a132347 (diff)
downloadlibvfio-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.c46
-rw-r--r--lib/muser_ctx.c64
2 files changed, 58 insertions, 52 deletions
diff --git a/lib/dma.c b/lib/dma.c
index 96b12c5..b47652d 100644
--- a/lib/dma.c
+++ b/lib/dma.c
@@ -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,