diff options
author | Thanos Makatos <thanos.makatos@nutanix.com> | 2021-05-20 17:10:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-20 17:10:51 +0100 |
commit | cfe9901919943f14961e1da1c4a823336ff79555 (patch) | |
tree | 2b5d8915bbbea8d239684e3334c9926fb910fc2c /test | |
parent | 947941de95bf2c3f723b37151d67fb129fd01841 (diff) | |
download | libvfio-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.c | 136 | ||||
-rw-r--r-- | test/mocks.h | 5 | ||||
-rw-r--r-- | test/unit-tests.c | 21 |
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 |