diff options
-rw-r--r-- | docs/vfio-user.rst | 5 | ||||
-rw-r--r-- | include/vfio-user.h | 3 | ||||
-rw-r--r-- | lib/libvfio-user.c | 25 | ||||
-rw-r--r-- | samples/client.c | 13 | ||||
-rw-r--r-- | test/py/libvfio_user.py | 2 | ||||
-rw-r--r-- | test/py/test_dma_unmap.py | 34 |
6 files changed, 80 insertions, 2 deletions
diff --git a/docs/vfio-user.rst b/docs/vfio-user.rst index 1b2095e..e912fb3 100644 --- a/docs/vfio-user.rst +++ b/docs/vfio-user.rst @@ -612,6 +612,8 @@ The request payload for this message is a structure of the following format: | | +=====+=======================+ | | | | 0 | get dirty page bitmap | | | | +-----+-----------------------+ | +| | | 1 | unmap all regions | | +| | +-----+-----------------------+ | +--------------+--------+------------------------+ | address | 8 | 8 | +--------------+--------+------------------------+ @@ -625,6 +627,9 @@ The request payload for this message is a structure of the following format: populated before unmapping the DMA region. The client must provide a `VFIO Bitmap`_ structure, explained below, immediately following this entry. + * *unmap all regions* indicates to unmap all the regions previously + mapped via `VFIO_USER_DMA_MAP`. This flag cannot be combined with + *get dirty page bitmap* and expects *address* and *size* to be 0. * *address* is the base DMA address of the DMA region. * *size* is the size of the DMA region. diff --git a/include/vfio-user.h b/include/vfio-user.h index 0aca789..b5e8962 100644 --- a/include/vfio-user.h +++ b/include/vfio-user.h @@ -133,6 +133,9 @@ struct vfio_user_dma_unmap { #ifndef VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP #define VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP (1 << 0) #endif +#ifndef VFIO_DMA_UNMAP_FLAG_ALL +#define VFIO_DMA_UNMAP_FLAG_ALL (1 << 1) +#endif uint32_t flags; uint64_t addr; uint64_t size; diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 4e6b81f..3cb30ba 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -545,7 +545,8 @@ handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, struct vfio_user_dma_unmap *dma_unmap) { size_t out_size; - int ret; + int ret = 0; + bool unmap_all = false; char rstr[1024]; assert(vfu_ctx != NULL); @@ -558,6 +559,12 @@ handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, return ERROR_INT(EINVAL); } + if ((dma_unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) && + (dma_unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL)) { + vfu_log(vfu_ctx, LOG_ERR, "invalid DMA flags=%#x", dma_unmap->flags); + return ERROR_INT(EINVAL); + } + snprintf(rstr, sizeof(rstr), "[%#lx, %#lx) flags=%#x", dma_unmap->addr, dma_unmap->addr + dma_unmap->size, dma_unmap->flags); @@ -585,6 +592,13 @@ handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, * the DMA controller. */ out_size += sizeof(*dma_unmap->bitmap) + dma_unmap->bitmap->size; + } else if (dma_unmap->flags == VFIO_DMA_UNMAP_FLAG_ALL) { + if (dma_unmap->addr || dma_unmap->size) { + vfu_log(vfu_ctx, LOG_ERR, "bad addr=%#lx or size=%#lx, expected " + "both to be zero", dma_unmap->addr, dma_unmap->size); + return ERROR_INT(EINVAL); + } + unmap_all = true; } else if (dma_unmap->flags != 0) { vfu_log(vfu_ctx, LOG_ERR, "bad flags=%#x", dma_unmap->flags); return ERROR_INT(ENOTSUP); @@ -596,6 +610,12 @@ handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, } memcpy(msg->out_data, dma_unmap, sizeof(*dma_unmap)); + if (unmap_all) { + dma_controller_remove_all_regions(vfu_ctx->dma, + vfu_ctx->dma_unregister, vfu_ctx); + goto out; + } + if (dma_unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) { memcpy(msg->out_data + sizeof(*dma_unmap), dma_unmap->bitmap, sizeof(*dma_unmap->bitmap)); ret = dma_controller_dirty_page_get(vfu_ctx->dma, @@ -621,7 +641,10 @@ handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg, "failed to remove DMA region %s: %m", rstr); return ERROR_INT(ret); } + +out: msg->out_size = out_size; + return ret; } diff --git a/samples/client.c b/samples/client.c index ef3202c..80a84d4 100644 --- a/samples/client.c +++ b/samples/client.c @@ -1302,6 +1302,19 @@ int main(int argc, char *argv[]) handle_dma_io(sock, dma_regions + server_max_fds, nr_dma_regions - server_max_fds, dma_region_fds + server_max_fds); + + struct vfio_user_dma_unmap r = { + .argsz = sizeof(r), + .addr = 0, + .size = 0, + .flags = VFIO_DMA_UNMAP_FLAG_ALL + }; + ret = tran_sock_msg(sock, 8, VFIO_USER_DMA_UNMAP, &r, sizeof(r), + NULL, &r, sizeof(r)); + if (ret < 0) { + err(EXIT_FAILURE, "failed to unmap all DMA regions"); + } + return 0; } diff --git a/test/py/libvfio_user.py b/test/py/libvfio_user.py index c7e3765..bf3e9cd 100644 --- a/test/py/libvfio_user.py +++ b/test/py/libvfio_user.py @@ -97,6 +97,8 @@ VFIO_IRQ_SET_ACTION_MASK = (1 << 3) VFIO_IRQ_SET_ACTION_UNMASK = (1 << 4) VFIO_IRQ_SET_ACTION_TRIGGER = (1 << 5) +VFIO_DMA_UNMAP_FLAG_ALL = (1 << 1) + # libvfio-user defines VFU_TRANS_SOCK = 0 diff --git a/test/py/test_dma_unmap.py b/test/py/test_dma_unmap.py index 0200c43..f070ede 100644 --- a/test/py/test_dma_unmap.py +++ b/test/py/test_dma_unmap.py @@ -65,7 +65,7 @@ def test_dma_unmap_bad_argsz(): def test_dma_unmap_invalid_flags(): payload = vfio_user_dma_unmap(argsz=len(vfio_user_dma_unmap()), - flags=0x2323, addr=0x1000, size=4096) + flags=0x4, addr=0x1000, size=4096) msg(ctx, sock, VFIO_USER_DMA_UNMAP, payload, expect=errno.ENOTSUP) def test_dma_unmap(): @@ -74,6 +74,38 @@ def test_dma_unmap(): flags=0, addr=0x1000, size=4096) msg(ctx, sock, VFIO_USER_DMA_UNMAP, payload) +def test_dma_unmap_all(): + + for i in range(0, MAX_DMA_REGIONS): + payload = vfio_user_dma_map(argsz=len(vfio_user_dma_map()), + flags=(VFIO_USER_F_DMA_REGION_READ | + VFIO_USER_F_DMA_REGION_WRITE), + offset=0, addr=0x1000 * i, size=4096) + + msg(ctx, sock, VFIO_USER_DMA_MAP, payload) + + payload = vfio_user_dma_unmap(argsz=len(vfio_user_dma_unmap()), + flags=VFIO_DMA_UNMAP_FLAG_ALL, addr=0, size=0) + + msg(ctx, sock, VFIO_USER_DMA_UNMAP, payload) + +def test_dma_unmap_all_invalid_addr(): + + payload = vfio_user_dma_unmap(argsz=len(vfio_user_dma_unmap()), + flags=VFIO_DMA_UNMAP_FLAG_ALL, addr=0x10000, size=4096) + + msg(ctx, sock, VFIO_USER_DMA_UNMAP, payload, expect=errno.EINVAL) + +def test_dma_unmap_all_invalid_flags(): + + payload = vfio_user_dma_unmap(argsz=len(vfio_user_dma_unmap()), + flags=(VFIO_DMA_UNMAP_FLAG_ALL | VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP), + addr=0, size=0) + + msg(ctx, sock, VFIO_USER_DMA_UNMAP, payload, expect=errno.EINVAL) + def test_dma_unmap_cleanup(): disconnect_client(ctx, sock) vfu_destroy_ctx(ctx) + +# ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab |