diff options
-rw-r--r-- | include/libvfio-user.h | 6 | ||||
-rw-r--r-- | lib/dma.c | 78 | ||||
-rw-r--r-- | lib/dma.h | 13 | ||||
-rw-r--r-- | lib/irq.c | 2 | ||||
-rw-r--r-- | lib/libvfio-user.c | 19 | ||||
-rw-r--r-- | lib/pci.c | 1 | ||||
-rw-r--r-- | lib/private.h | 8 | ||||
-rw-r--r-- | lib/tran_sock.c | 1 | ||||
-rw-r--r-- | samples/server.c | 14 | ||||
-rw-r--r-- | test/mocks.c | 1 | ||||
-rw-r--r-- | test/unit-tests.c | 17 |
11 files changed, 88 insertions, 72 deletions
diff --git a/include/libvfio-user.h b/include/libvfio-user.h index a43f38a..f2876a1 100644 --- a/include/libvfio-user.h +++ b/include/libvfio-user.h @@ -404,9 +404,9 @@ typedef void (vfu_dma_register_cb_t)(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info); * This is required if you want to be able to access guest memory directly via * a mapping. * - * The callback should return 0 on success, errno on failure (although - * unregister should not fail: this will not stop a guest from unregistering the - * region). + * The callback should return 0 on success, -1 with errno set on failure + * (although unregister should not fail: this will not stop a guest from + * unregistering the region). * * @vfu_ctx: the libvfio-user context * @info: the DMA info @@ -156,11 +156,11 @@ MOCK_DEFINE(dma_controller_remove_region)(dma_controller_t *dma, err = dma_unregister(data, ®ion->info); if (err != 0) { + err = errno; vfu_log(dma->vfu_ctx, LOG_ERR, - "failed to dma_unregister() DMA region [%p, %p): %s", - region->info.iova.iov_base, iov_end(®ion->info.iova), - strerror(err)); - return -err; + "failed to dma_unregister() DMA region [%p, %p): %m", + region->info.iova.iov_base, iov_end(®ion->info.iova)); + return ERROR_INT(err); } assert(region->refcnt == 0); @@ -174,7 +174,7 @@ MOCK_DEFINE(dma_controller_remove_region)(dma_controller_t *dma, array_remove(&dma->regions, sizeof (*region), idx, &dma->nregions); return 0; } - return -ENOENT; + return ERROR_INT(ENOENT); } void @@ -229,7 +229,7 @@ dma_map_region(dma_controller_t *dma, dma_memory_region_t *region) region->fd, offset); if (mmap_base == MAP_FAILED) { - return -errno; + return -1; } // Do not dump. @@ -258,7 +258,6 @@ MOCK_DEFINE(dma_controller_add_region)(dma_controller_t *dma, int page_size = 0; char rstr[1024]; int idx; - int ret; assert(dma != NULL); @@ -274,8 +273,7 @@ MOCK_DEFINE(dma_controller_add_region)(dma_controller_t *dma, if (offset != region->offset) { vfu_log(dma->vfu_ctx, LOG_ERR, "bad offset for new DMA region " "%s; existing=%#lx", rstr, region->offset); - ret = -EINVAL; - goto out; + return ERROR_INT(EINVAL); } if (!fds_are_same_file(region->fd, fd)) { /* @@ -286,14 +284,12 @@ MOCK_DEFINE(dma_controller_add_region)(dma_controller_t *dma, */ vfu_log(dma->vfu_ctx, LOG_ERR, "bad fd for new DMA region %s; " "existing=%d", rstr, region->fd); - ret = -EINVAL; - goto out; + return ERROR_INT(EINVAL); } if (region->info.prot != prot) { vfu_log(dma->vfu_ctx, LOG_ERR, "bad prot for new DMA region " "%s; existing=%#x", rstr, region->info.prot); - ret = -EINVAL; - goto out; + return ERROR_INT(EINVAL); } return idx; } @@ -306,15 +302,13 @@ MOCK_DEFINE(dma_controller_add_region)(dma_controller_t *dma, vfu_log(dma->vfu_ctx, LOG_INFO, "new DMA region %s overlaps with " "DMA region [%p, %p)", rstr, region->info.iova.iov_base, iov_end(®ion->info.iova)); - ret = -EINVAL; - goto out; + return ERROR_INT(EINVAL); } } if (dma->nregions == dma->max_regions) { vfu_log(dma->vfu_ctx, LOG_ERR, "hit max regions %d", dma->max_regions); - ret = -EINVAL; - goto out; + return ERROR_INT(EINVAL); } idx = dma->nregions; @@ -324,8 +318,7 @@ MOCK_DEFINE(dma_controller_add_region)(dma_controller_t *dma, page_size = fd_get_blocksize(fd); if (page_size < 0) { vfu_log(dma->vfu_ctx, LOG_ERR, "bad page size %d", page_size); - ret = -EINVAL; - goto out; + return ERROR_INT(EINVAL); } } page_size = MAX(page_size, getpagesize()); @@ -340,26 +333,24 @@ MOCK_DEFINE(dma_controller_add_region)(dma_controller_t *dma, region->fd = fd; if (fd != -1) { - ret = dma_map_region(dma, region); + int ret = dma_map_region(dma, region); if (ret != 0) { + ret = errno; vfu_log(dma->vfu_ctx, LOG_ERR, - "failed to memory map DMA region %s: %s", rstr, - strerror(-ret)); + "failed to memory map DMA region %s: %m", rstr); if (close(region->fd) == -1) { vfu_log(dma->vfu_ctx, LOG_WARNING, "failed to close fd %d: %m", region->fd); } - goto out; + + return ERROR_INT(ret); } } - ret = idx; dma->nregions++; - -out: - return ret; + return idx; } int @@ -407,8 +398,7 @@ out: if (!found) { // There is still a region which was not found. assert(len > 0); - errno = ENOENT; - return -1; + return ERROR_INT(ENOENT); } else if (cnt > max_sg) { cnt = -cnt - 1; } @@ -420,10 +410,10 @@ static ssize_t get_bitmap_size(size_t region_size, size_t pgsize) { if (pgsize == 0) { - return -EINVAL; + return ERROR_INT(EINVAL); } if (region_size < pgsize) { - return -EINVAL; + return ERROR_INT(EINVAL); } size_t nr_pages = (region_size / pgsize) + (region_size % pgsize != 0); return (nr_pages / CHAR_BIT) + (nr_pages % CHAR_BIT != 0); @@ -431,22 +421,22 @@ get_bitmap_size(size_t region_size, size_t pgsize) int dma_controller_dirty_page_logging_start(dma_controller_t *dma, size_t pgsize) { - int i; + size_t i; assert(dma != NULL); if (pgsize == 0) { - return -EINVAL; + return ERROR_INT(EINVAL); } if (dma->dirty_pgsize > 0) { if (dma->dirty_pgsize != pgsize) { - return -EINVAL; + return ERROR_INT(EINVAL); } return 0; } - for (i = 0; i < dma->nregions; i++) { + for (i = 0; i < (size_t)dma->nregions; i++) { dma_memory_region_t *region = &dma->regions[i]; ssize_t bitmap_size; @@ -457,27 +447,30 @@ int dma_controller_dirty_page_logging_start(dma_controller_t *dma, size_t pgsize } region->dirty_bitmap = calloc(bitmap_size, sizeof(char)); if (region->dirty_bitmap == NULL) { - int j, ret = -errno; + int ret = errno; + size_t j; + for (j = 0; j < i; j++) { region = &dma->regions[j]; free(region->dirty_bitmap); region->dirty_bitmap = NULL; } - return ret; + return ERROR_INT(ret); } } dma->dirty_pgsize = pgsize; return 0; } -int dma_controller_dirty_page_logging_stop(dma_controller_t *dma) +void +dma_controller_dirty_page_logging_stop(dma_controller_t *dma) { int i; assert(dma != NULL); if (dma->dirty_pgsize == 0) { - return 0; + return; } for (i = 0; i < dma->nregions; i++) { @@ -485,7 +478,6 @@ int dma_controller_dirty_page_logging_stop(dma_controller_t *dma) dma->regions[i].dirty_bitmap = NULL; } dma->dirty_pgsize = 0; - return 0; } int @@ -507,11 +499,11 @@ dma_controller_dirty_page_get(dma_controller_t *dma, vfu_dma_addr_t addr, */ ret = dma_addr_to_sg(dma, addr, len, &sg, 1, PROT_NONE); if (ret != 1 || sg.dma_addr != addr || sg.length != len) { - return -ENOTSUP; + return ERROR_INT(ENOTSUP); } if (pgsize != dma->dirty_pgsize) { - return -EINVAL; + return ERROR_INT(EINVAL); } bitmap_size = get_bitmap_size(len, pgsize); @@ -524,7 +516,7 @@ dma_controller_dirty_page_get(dma_controller_t *dma, vfu_dma_addr_t addr, * expects to receive. */ if (size != (size_t)bitmap_size) { - return -EINVAL; + return ERROR_INT(EINVAL); } region = &dma->regions[sg.region]; @@ -76,6 +76,7 @@ #include "libvfio-user.h" #include "common.h" +#include "private.h" #define iov_end(iov) ((iov)->iov_base + (iov)->iov_len) @@ -89,7 +90,7 @@ typedef struct { char *dirty_bitmap; // Dirty page bitmap } dma_memory_region_t; -typedef struct { +typedef struct dma_controller { int max_regions; int nregions; struct vfu_ctx *vfu_ctx; @@ -187,8 +188,7 @@ dma_init_sg(const dma_controller_t *dma, dma_sg_t *sg, vfu_dma_addr_t dma_addr, const dma_memory_region_t *const region = &dma->regions[region_index]; if ((prot & PROT_WRITE) && !(region->info.prot & PROT_WRITE)) { - errno = EACCES; - return -1; + return ERROR_INT(EACCES); } sg->dma_addr = region->info.iova.iov_base; @@ -260,12 +260,12 @@ dma_map_sg(dma_controller_t *dma, const dma_sg_t *sg, struct iovec *iov, for (i = 0; i < cnt; i++) { if (sg[i].region >= dma->nregions) { - return -EINVAL; + return ERROR_INT(EINVAL); } region = &dma->regions[sg[i].region]; if (region->info.vaddr == NULL) { - return -EFAULT; + return ERROR_INT(EFAULT); } vfu_log(dma->vfu_ctx, LOG_DEBUG, "map %p-%p", @@ -304,13 +304,12 @@ dma_unmap_sg(dma_controller_t *dma, const dma_sg_t *sg, sg[i].dma_addr + sg[i].offset + sg[i].length); r->refcnt--; } - return; } int dma_controller_dirty_page_logging_start(dma_controller_t *dma, size_t pgsize); -int +void dma_controller_dirty_page_logging_stop(dma_controller_t *dma); int @@ -30,8 +30,10 @@ * */ +#include <assert.h> #include <errno.h> #include <limits.h> +#include <stdlib.h> #include <sys/eventfd.h> #include "irq.h" diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 0440351..f4aa804 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -532,11 +532,12 @@ handle_dma_map_or_unmap(vfu_ctx_t *vfu_ctx, uint32_t size, bool map, 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); } - vfu_log(vfu_ctx, LOG_ERR, "failed to add DMA region %s: %s", - rstr, strerror(-ret)); break; } @@ -553,8 +554,9 @@ handle_dma_map_or_unmap(vfu_ctx_t *vfu_ctx, uint32_t size, bool map, vfu_ctx->dma_unregister, vfu_ctx); if (ret < 0) { - vfu_log(vfu_ctx, LOG_ERR, "failed to remove DMA region %s: %s", - rstr, strerror(-ret)); + ret = -errno; + vfu_log(vfu_ctx, LOG_ERR, "failed to remove DMA region %s: %m", + rstr); break; } } @@ -603,6 +605,7 @@ handle_dirty_pages_get(vfu_ctx_t *vfu_ctx, r->bitmap.size, (char**)&((*iovecs)[i].iov_base)); if (ret != 0) { + ret = -errno; goto out; } (*iovecs)[i].iov_len = r->bitmap.size; @@ -637,8 +640,12 @@ MOCK_DEFINE(handle_dirty_pages)(vfu_ctx_t *vfu_ctx, uint32_t size, if (dirty_bitmap->flags & VFIO_IOMMU_DIRTY_PAGES_FLAG_START) { ret = dma_controller_dirty_page_logging_start(vfu_ctx->dma, migration_get_pgsize(vfu_ctx->migration)); + if (ret == -1) { + ret = -errno; + } } else if (dirty_bitmap->flags & VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP) { - ret = dma_controller_dirty_page_logging_stop(vfu_ctx->dma); + dma_controller_dirty_page_logging_stop(vfu_ctx->dma); + ret = 0; } else if (dirty_bitmap->flags & VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP) { ret = handle_dirty_pages_get(vfu_ctx, iovecs, nr_iovecs, (struct vfio_iommu_type1_dirty_bitmap_get*)(dirty_bitmap + 1), @@ -1520,7 +1527,7 @@ vfu_map_sg(vfu_ctx_t *vfu_ctx, const dma_sg_t *sg, ret = dma_map_sg(vfu_ctx->dma, sg, iov, cnt); if (ret < 0) { - return ERROR_INT(-ret); + return -1; } return 0; @@ -33,6 +33,7 @@ #include <assert.h> #include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <sys/param.h> diff --git a/lib/private.h b/lib/private.h index 49f9152..fde5e3c 100644 --- a/lib/private.h +++ b/lib/private.h @@ -33,8 +33,10 @@ #ifndef LIB_VFIO_USER_PRIVATE_H #define LIB_VFIO_USER_PRIVATE_H +#include <errno.h> + #include "pci_caps.h" -#include "dma.h" +#include "common.h" static inline int ERROR_INT(int err) @@ -109,9 +111,11 @@ struct pci_dev { size_t nr_ext_caps; }; +struct dma_controller; + struct vfu_ctx { void *pvt; - dma_controller_t *dma; + struct dma_controller *dma; vfu_reset_cb_t *reset; int log_level; vfu_log_fn_t *log; diff --git a/lib/tran_sock.c b/lib/tran_sock.c index ce3430a..a1d6a1a 100644 --- a/lib/tran_sock.c +++ b/lib/tran_sock.c @@ -30,6 +30,7 @@ * */ +#include <assert.h> #include <errno.h> #include <fcntl.h> #include <limits.h> diff --git a/samples/server.c b/samples/server.c index f9bde30..a449bb6 100644 --- a/samples/server.c +++ b/samples/server.c @@ -45,6 +45,7 @@ #include "common.h" #include "libvfio-user.h" +#include "private.h" #include "tran_sock.h" struct dma_regions { @@ -184,7 +185,7 @@ dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) } } - return -EINVAL; + return ERROR_INT(EINVAL); } static void @@ -219,10 +220,9 @@ static void do_dma_io(vfu_ctx_t *vfu_ctx, struct server_data *server_data) (vfu_dma_addr_t)server_data->regions[0].iova.iov_base, count, &sg, 1, PROT_WRITE); if (ret < 0) { - errx(EXIT_FAILURE, "failed to map %p-%p: %s", - server_data->regions[0].iova.iov_base, - server_data->regions[0].iova.iov_base + count -1, - strerror(-ret)); + err(EXIT_FAILURE, "failed to map %p-%p", + server_data->regions[0].iova.iov_base, + server_data->regions[0].iova.iov_base + count -1); } memset(buf, 'A', count); @@ -231,7 +231,7 @@ static void do_dma_io(vfu_ctx_t *vfu_ctx, struct server_data *server_data) server_data->regions[0].iova.iov_base, count); ret = vfu_dma_write(vfu_ctx, &sg, buf); if (ret < 0) { - errx(EXIT_FAILURE, "vfu_dma_write failed: %s", strerror(-ret)); + err(EXIT_FAILURE, "vfu_dma_write failed"); } memset(buf, 0, count); @@ -239,7 +239,7 @@ static void do_dma_io(vfu_ctx_t *vfu_ctx, struct server_data *server_data) server_data->regions[0].iova.iov_base, count); ret = vfu_dma_read(vfu_ctx, &sg, buf); if (ret < 0) { - errx(EXIT_FAILURE, "vfu_dma_read failed: %s", strerror(-ret)); + err(EXIT_FAILURE, "vfu_dma_read failed"); } get_md5sum(buf, count, md5sum2); for(i = 0; i < MD5_DIGEST_LENGTH; i++) { diff --git a/test/mocks.c b/test/mocks.c index b01011e..7121826 100644 --- a/test/mocks.c +++ b/test/mocks.c @@ -125,6 +125,7 @@ dma_controller_add_region(dma_controller_t *dma, void *dma_addr, check_expected(fd); check_expected(offset); check_expected(prot); + errno = mock(); return mock(); } diff --git a/test/unit-tests.c b/test/unit-tests.c index 3b1d227..1e245a5 100644 --- a/test/unit-tests.c +++ b/test/unit-tests.c @@ -95,6 +95,7 @@ test_dma_map_without_fd(void **state UNUSED) patch("dma_controller_add_region"); will_return(dma_controller_add_region, 0); + will_return(dma_controller_add_region, 0); expect_value(dma_controller_add_region, dma, vfu_ctx.dma); expect_value(dma_controller_add_region, dma_addr, r.addr); expect_value(dma_controller_add_region, size, r.size); @@ -164,6 +165,7 @@ test_dma_add_regions_mixed(void **state UNUSED) patch("dma_controller_add_region"); /* 1st region */ will_return(dma_controller_add_region, 0); + will_return(dma_controller_add_region, 0); expect_value(dma_controller_add_region, dma, vfu_ctx.dma); expect_value(dma_controller_add_region, dma_addr, r[0].addr); expect_value(dma_controller_add_region, size, r[0].size); @@ -174,6 +176,7 @@ test_dma_add_regions_mixed(void **state UNUSED) expect_check(mock_dma_register, info, check_dma_info, &dma->regions[0].info); /* 2nd region */ + will_return(dma_controller_add_region, 0); will_return(dma_controller_add_region, 1); expect_value(dma_controller_add_region, dma, vfu_ctx.dma); expect_value(dma_controller_add_region, dma_addr, r[1].addr); @@ -231,6 +234,7 @@ test_dma_add_regions_mixed_partial_failure(void **state UNUSED) expect_value(dma_controller_add_region, offset, r[0].offset); expect_value(dma_controller_add_region, prot, r[0].prot); will_return(dma_controller_add_region, 0); + will_return(dma_controller_add_region, 0); /* 2nd region */ expect_value(dma_controller_add_region, dma, vfu_ctx.dma); @@ -240,6 +244,7 @@ test_dma_add_regions_mixed_partial_failure(void **state UNUSED) expect_value(dma_controller_add_region, offset, r[1].offset); expect_value(dma_controller_add_region, prot, r[1].prot); will_return(dma_controller_add_region, 0); + will_return(dma_controller_add_region, 0); /* 3rd region */ expect_value(dma_controller_add_region, dma, vfu_ctx.dma); @@ -248,13 +253,14 @@ test_dma_add_regions_mixed_partial_failure(void **state UNUSED) expect_value(dma_controller_add_region, fd, fds[1]); expect_value(dma_controller_add_region, offset, r[2].offset); expect_value(dma_controller_add_region, prot, r[2].prot); - will_return(dma_controller_add_region, -0x1234); + will_return(dma_controller_add_region, EREMOTEIO); + will_return(dma_controller_add_region, -1); patch("close"); expect_value(close, fd, 0xb); will_return(close, 0); - assert_int_equal(-0x1234, + assert_int_equal(-EREMOTEIO, handle_dma_map_or_unmap(&vfu_ctx, ARRAY_SIZE(r) * sizeof(struct vfio_user_dma_region), true, fds, 2, r)); @@ -280,6 +286,7 @@ test_dma_map_return_value(void **state UNUSED) expect_value(dma_controller_add_region, fd, -1); expect_value(dma_controller_add_region, offset, r.offset); expect_value(dma_controller_add_region, prot, r.prot); + will_return(dma_controller_add_region, 0); will_return(dma_controller_add_region, 2); assert_int_equal(0, @@ -1254,11 +1261,13 @@ test_dma_map_sg(void **state UNUSED) dma->nregions = 1; /* bad region */ - assert_int_equal(-EINVAL, dma_map_sg(dma, &sg, &iovec, 1)); + assert_int_equal(-1, dma_map_sg(dma, &sg, &iovec, 1)); + assert_int_equal(EINVAL, errno); /* w/o fd */ sg.region = 0; - assert_int_equal(-EFAULT, dma_map_sg(dma, &sg, &iovec, 1)); + assert_int_equal(-1, dma_map_sg(dma, &sg, &iovec, 1)); + assert_int_equal(EFAULT, errno); /* w/ fd */ dma->regions[0].info.vaddr = (void *)0xdead0000; |