aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorThanos Makatos <thanos.makatos@nutanix.com>2021-05-20 17:10:51 +0100
committerGitHub <noreply@github.com>2021-05-20 17:10:51 +0100
commitcfe9901919943f14961e1da1c4a823336ff79555 (patch)
tree2b5d8915bbbea8d239684e3334c9926fb910fc2c /test
parent947941de95bf2c3f723b37151d67fb129fd01841 (diff)
downloadlibvfio-user-cfe9901919943f14961e1da1c4a823336ff79555.zip
libvfio-user-cfe9901919943f14961e1da1c4a823336ff79555.tar.gz
libvfio-user-cfe9901919943f14961e1da1c4a823336ff79555.tar.bz2
migration: various dirty page tracking fixes (#457)
- document how to use a vfio-user device with libvirt - document how to use SPDK's nvmf/vfio-user target with libvirt - replace vfio_bitmap with vfio_user_bitmap and vfio_iommu_type1_dirty_bitmap_get with vfio_user_bitmap_range - fix bug for calculating number of pages needed for dirty page bitmap - align number of bytes for dirty page bitmap to QWORD - add debug messages around dirty page tracking - only support flags=0 when doing DMA unmap - set device state to running after reset - allow region read/write even if device is in stopped state - allow transitioning from stopped/stop-and-copy state to running state - fix unit tests Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com> Reviewed-by: John Levon <john.levon@nutanix.com>
Diffstat (limited to 'test')
-rw-r--r--test/mocks.c136
-rw-r--r--test/mocks.h5
-rw-r--r--test/unit-tests.c21
3 files changed, 153 insertions, 9 deletions
diff --git a/test/mocks.c b/test/mocks.c
index be9767f..5a2b55f 100644
--- a/test/mocks.c
+++ b/test/mocks.c
@@ -44,6 +44,7 @@
#include "mocks.h"
#include "private.h"
#include "tran_sock.h"
+#include "migration_priv.h"
struct function
{
@@ -67,6 +68,14 @@ static struct function funcs[] = {
{ .name = "process_request" },
{ .name = "should_exec_command" },
{ .name = "tran_sock_send_iovec" },
+ { .name = "migration_region_access_registers" },
+ { .name = "handle_dirty_pages_get" },
+ { .name = "handle_device_state" },
+ {. name = "vfio_migr_state_transition_is_valid" },
+ { .name = "state_trans_notify" },
+ { .name = "migr_trans_to_valid_state" },
+ { .name = "migr_state_vfio_to_vfu" },
+ { .name = "migr_state_transition" },
/* system libs */
{ .name = "bind" },
{ .name = "close" },
@@ -258,6 +267,116 @@ handle_dirty_pages(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
return mock();
}
+ssize_t
+migration_region_access_registers(vfu_ctx_t *vfu_ctx, char *buf, size_t count,
+ loff_t pos, bool is_write)
+{
+ if (!is_patched("migration_region_access_registers")) {
+ return __real_migration_region_access_registers(vfu_ctx, buf, count,
+ pos, is_write);
+ }
+ check_expected(vfu_ctx);
+ check_expected(buf);
+ check_expected(count);
+ check_expected(pos);
+ check_expected(is_write);
+ errno = mock();
+ return mock();
+}
+
+int
+handle_dirty_pages_get(vfu_ctx_t *vfu_ctx,
+ struct iovec **iovecs, size_t *nr_iovecs,
+ struct vfio_user_bitmap_range *ranges, uint32_t size)
+{
+ if (!is_patched("handle_dirty_pages_get")) {
+ return __real_handle_dirty_pages_get(vfu_ctx, iovecs, nr_iovecs,
+ ranges, size);
+ }
+ check_expected(vfu_ctx);
+ check_expected(iovecs);
+ check_expected(nr_iovecs);
+ check_expected(ranges);
+ check_expected(size);
+ return mock();
+}
+
+ssize_t
+handle_device_state(vfu_ctx_t *vfu_ctx, struct migration *migr,
+ uint32_t device_state, bool notify) {
+
+ if (!is_patched("handle_device_state")) {
+ return __real_handle_device_state(vfu_ctx, migr, device_state,
+ notify);
+ }
+ check_expected(vfu_ctx);
+ check_expected(migr);
+ check_expected(device_state);
+ check_expected(notify);
+ return mock();
+}
+
+void
+migr_state_transition(struct migration *migr, enum migr_iter_state state)
+{
+ if (!is_patched("migr_state_transition")) {
+ __real_migr_state_transition(migr, state);
+ return;
+ }
+ check_expected(migr);
+ check_expected(state);
+}
+
+bool
+vfio_migr_state_transition_is_valid(uint32_t from, uint32_t to)
+{
+ if (!is_patched("vfio_migr_state_transition_is_valid")) {
+ return __real_vfio_migr_state_transition_is_valid(from, to);
+ }
+ check_expected(from);
+ check_expected(to);
+ return mock();
+}
+
+int
+state_trans_notify(vfu_ctx_t *vfu_ctx, int (*fn)(vfu_ctx_t*, vfu_migr_state_t),
+ uint32_t vfio_device_state)
+{
+ if (!is_patched("state_trans_notify")) {
+ return __real_state_trans_notify(vfu_ctx, fn, vfio_device_state);
+ }
+ check_expected(vfu_ctx);
+ check_expected(fn);
+ check_expected(vfio_device_state);
+ errno = mock();
+ return mock();
+}
+
+ssize_t
+migr_trans_to_valid_state(vfu_ctx_t *vfu_ctx, struct migration *migr,
+ uint32_t device_state, bool notify)
+{
+ if (!is_patched("migr_trans_to_valid_state")) {
+ return __real_migr_trans_to_valid_state(vfu_ctx, migr, device_state,
+ notify);
+ }
+ check_expected(vfu_ctx);
+ check_expected(migr);
+ check_expected(device_state);
+ check_expected(notify);
+ return mock();
+}
+
+vfu_migr_state_t
+migr_state_vfio_to_vfu(uint32_t vfio_device_state)
+{
+ if (!is_patched("migr_state_vfio_to_vfu")) {
+ return __real_migr_state_vfio_to_vfu(vfio_device_state);
+ }
+ check_expected(vfio_device_state);
+ return mock();
+}
+
/* Always mocked. */
void
mock_dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info)
@@ -274,6 +393,23 @@ mock_dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info)
return mock();
}
+int
+mock_reset_cb(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type)
+{
+ check_expected(vfu_ctx);
+ check_expected(type);
+ return mock();
+}
+
+
+int
+mock_notify_migr_state_trans_cb(vfu_ctx_t *vfu_ctx, vfu_migr_state_t vfu_state)
+{
+ check_expected(vfu_ctx);
+ check_expected(vfu_state);
+ return mock();
+}
+
/* System-provided funcs. */
int
diff --git a/test/mocks.h b/test/mocks.h
index 496cc54..7547956 100644
--- a/test/mocks.h
+++ b/test/mocks.h
@@ -38,4 +38,9 @@ void mock_dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info);
int mock_dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info);
+int mock_reset_cb(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type);
+
+int mock_notify_migr_state_trans_cb(vfu_ctx_t *vfu_ctx,
+ vfu_migr_state_t vfu_state);
+
/* ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/unit-tests.c b/test/unit-tests.c
index 029e8d2..cac4445 100644
--- a/test/unit-tests.c
+++ b/test/unit-tests.c
@@ -845,9 +845,10 @@ test_migration_state_transitions(void **state UNUSED)
bool (*f)(uint32_t, uint32_t) = vfio_migr_state_transition_is_valid;
uint32_t i, j;
- /* from stopped (000b): all transitions are invalid */
+ /* from stopped (000b): all transitions are invalid except to running */
assert_true(f(0, 0));
- for (i = 1; i < 8; i++) {
+ assert_true(f(0, 1));
+ for (i = 2; i < 8; i++) {
assert_false(f(0, i));
}
@@ -863,7 +864,7 @@ test_migration_state_transitions(void **state UNUSED)
/* from stop-and-copy (010b) */
assert_true(f(2, 0));
- assert_false(f(2, 1));
+ assert_true(f(2, 1));
assert_true(f(2, 2));
assert_false(f(2, 3));
assert_false(f(2, 4));
@@ -1107,28 +1108,30 @@ test_should_exec_command(UNUSED void **state)
patch("cmd_allowed_when_stopped_and_copying");
patch("device_is_stopped");
- /* XXX stopped and copying, command allowed */
+ /* TEST stopped and copying, command allowed */
will_return(device_is_stopped_and_copying, true);
expect_value(device_is_stopped_and_copying, migration, &migration);
will_return(cmd_allowed_when_stopped_and_copying, true);
expect_value(cmd_allowed_when_stopped_and_copying, cmd, 0xbeef);
assert_true(should_exec_command(&vfu_ctx, 0xbeef));
- /* XXX stopped and copying, command not allowed */
+ /* TEST stopped and copying, command not allowed */
will_return(device_is_stopped_and_copying, true);
expect_any(device_is_stopped_and_copying, migration);
will_return(cmd_allowed_when_stopped_and_copying, false);
expect_any(cmd_allowed_when_stopped_and_copying, cmd);
assert_false(should_exec_command(&vfu_ctx, 0xbeef));
- /* XXX stopped */
+ /* TEST stopped */
will_return(device_is_stopped_and_copying, false);
expect_any(device_is_stopped_and_copying, migration);
will_return(device_is_stopped, true);
expect_value(device_is_stopped, migration, &migration);
+ will_return(cmd_allowed_when_stopped_and_copying, false);
+ expect_value(cmd_allowed_when_stopped_and_copying, cmd, 0xbeef);
assert_false(should_exec_command(&vfu_ctx, 0xbeef));
- /* XXX none of the above */
+ /* TEST none of the above */
will_return(device_is_stopped_and_copying, false);
expect_any(device_is_stopped_and_copying, migration);
will_return(device_is_stopped, false);
@@ -1226,7 +1229,7 @@ test_dma_controller_dirty_page_get(void **state UNUSED)
{
dma_memory_region_t *r;
uint64_t len = UINT32_MAX + (uint64_t)10;
- char bp[131073];
+ char bp[0x20008]; /* must be QWORD aligned */
vfu_ctx.dma->nregions = 1;
r = &vfu_ctx.dma->regions[0];
@@ -1236,7 +1239,7 @@ test_dma_controller_dirty_page_get(void **state UNUSED)
vfu_ctx.dma->dirty_pgsize = 4096;
assert_int_equal(0, dma_controller_dirty_page_get(vfu_ctx.dma, (void *)0,
- len, 4096, 131073, (char **)&bp));
+ len, 4096, sizeof(bp), (char **)&bp));
}
int