aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/vfio-user.rst5
-rw-r--r--include/vfio-user.h3
-rw-r--r--lib/libvfio-user.c25
-rw-r--r--samples/client.c13
-rw-r--r--test/py/libvfio_user.py2
-rw-r--r--test/py/test_dma_unmap.py34
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