aboutsummaryrefslogtreecommitdiff
path: root/test/unit-tests.c
diff options
context:
space:
mode:
authorThanos Makatos <thanos.makatos@nutanix.com>2021-02-10 09:08:10 +0000
committerGitHub <noreply@github.com>2021-02-10 09:08:10 +0000
commit365ca96a97740332d3633090d850222d10bc9d70 (patch)
treebd9885cd57351c05ac12d63ef51a4e4e5b3eef7d /test/unit-tests.c
parentc5d11659c95c995acb77a71fe03c38b240ca43d9 (diff)
downloadlibvfio-user-365ca96a97740332d3633090d850222d10bc9d70.zip
libvfio-user-365ca96a97740332d3633090d850222d10bc9d70.tar.gz
libvfio-user-365ca96a97740332d3633090d850222d10bc9d70.tar.bz2
expose migration region (#305)
This patch exposes the fact that live migration is implemented as a special device region. Hiding this from the user doesn't offer much benefit since it only takes just a little bit of extra code for the user to handle it as a region. We do keep the migration callback functionality since this feature substantially simplifies supporting live migration from the device implementation's perspective. Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com> Co-authored-by: John Levon <john.levon@nutanix.com>
Diffstat (limited to 'test/unit-tests.c')
-rw-r--r--test/unit-tests.c176
1 files changed, 174 insertions, 2 deletions
diff --git a/test/unit-tests.c b/test/unit-tests.c
index c989d91..e3ad86e 100644
--- a/test/unit-tests.c
+++ b/test/unit-tests.c
@@ -39,6 +39,7 @@
#include <alloca.h>
#include <string.h>
#include <linux/pci_regs.h>
+#include <sys/param.h>
#include "dma.h"
#include "libvfio-user.h"
@@ -1202,11 +1203,158 @@ test_migration_state_transitions(void **state __attribute__ ((unused)))
* and provide a function to execute before and after each unit test.
*/
static int
-setup(void **state __attribute__((unused))) {
+setup(void **state __attribute__((unused)))
+{
unpatch_all();
return 0;
}
+static struct test_setup_migr_reg_dat {
+ vfu_ctx_t *v;
+ size_t rs; /* migration registers size */
+ size_t ds; /* migration data size */
+ size_t s; /* migration region size*/
+ const vfu_migration_callbacks_t c;
+} migr_reg_data = {
+ .c = {
+ .version = VFU_MIGR_CALLBACKS_VERS,
+ .transition = (void *)0x1,
+ .get_pending_bytes = (void *)0x2,
+ .prepare_data = (void *)0x3,
+ .read_data = (void *)0x4,
+ .write_data = (void *)0x5,
+ .data_written = (void *)0x6
+ }
+};
+
+static int
+setup_test_setup_migration_region(void **state)
+{
+ struct test_setup_migr_reg_dat *p = &migr_reg_data;
+ p->v = vfu_create_ctx(VFU_TRANS_SOCK, "test", 0, NULL,
+ VFU_DEV_TYPE_PCI);
+ if (p->v == NULL) {
+ return -1;
+ }
+ p->rs = ROUND_UP(sizeof(struct vfio_device_migration_info), sysconf(_SC_PAGE_SIZE));
+ p->ds = sysconf(_SC_PAGE_SIZE);
+ p->s = p->rs + p->ds;
+ *state = p;
+ return setup(state);
+}
+
+static vfu_ctx_t *
+get_vfu_ctx(void **state)
+{
+ return (*((struct test_setup_migr_reg_dat **)(state)))->v;
+}
+
+static int
+teardown_test_setup_migration_region(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ vfu_destroy_ctx(p->v);
+ return 0;
+}
+
+static void
+test_setup_migration_region_too_small(void **state)
+{
+ vfu_ctx_t *v = get_vfu_ctx(state);
+ int r = vfu_setup_region(v, VFU_PCI_DEV_MIGR_REGION_IDX,
+ vfu_get_migr_register_area_size() - 1, NULL,
+ VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1);
+ assert_int_equal(-1, r);
+ assert_int_equal(EINVAL, errno);
+}
+
+static void
+test_setup_migration_region_size_ok(void **state)
+{
+ vfu_ctx_t *v = get_vfu_ctx(state);
+ int r = vfu_setup_region(v, VFU_PCI_DEV_MIGR_REGION_IDX,
+ vfu_get_migr_register_area_size(), NULL,
+ VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1);
+ assert_int_equal(0, r);
+}
+
+static void
+test_setup_migration_region_fully_mappable(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s,
+ NULL, VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0,
+ 0xdeadbeef);
+ assert_int_equal(-1, r);
+ assert_int_equal(EINVAL, errno);
+}
+
+static void
+test_setup_migration_region_sparsely_mappable_over_migration_registers(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ struct iovec mmap_areas[] = {
+ [0] = {
+ .iov_base = 0,
+ .iov_len = p->rs
+ }
+ };
+ int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL,
+ VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, mmap_areas, 1, 0xdeadbeef);
+ assert_int_equal(-1, r);
+ assert_int_equal(EINVAL, errno);
+}
+
+static void
+test_setup_migration_region_sparsely_mappable_valid(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ struct iovec mmap_areas[] = {
+ [0] = {
+ .iov_base = (void *)p->rs,
+ .iov_len = p->ds
+ }
+ };
+ int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL,
+ VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, mmap_areas, 1,
+ 0xdeadbeef);
+ assert_int_equal(0, r);
+}
+
+static void
+test_setup_migration_callbacks_without_migration_region(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ assert_int_equal(-1, vfu_setup_device_migration_callbacks(p->v, &p->c, 0));
+ assert_int_equal(EINVAL, errno);
+}
+
+static void
+test_setup_migration_callbacks_bad_data_offset(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL,
+ VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1);
+ assert_int_equal(0, r);
+ r = vfu_setup_device_migration_callbacks(p->v, &p->c,
+ vfu_get_migr_register_area_size() - 1);
+ assert_int_equal(-1, r);
+}
+
+static void
+test_setup_migration_callbacks(void **state)
+{
+ struct test_setup_migr_reg_dat *p = *state;
+ int r = vfu_setup_region(p->v, VFU_PCI_DEV_MIGR_REGION_IDX, p->s, NULL,
+ VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE, NULL, 0, -1);
+ assert_int_equal(0, r);
+ r = vfu_setup_device_migration_callbacks(p->v, &p->c,
+ vfu_get_migr_register_area_size());
+ assert_int_equal(0, r);
+ assert_non_null(p->v->migration);
+ /* FIXME can't validate p->v->migration because it's a private strcut, need to move it out of lib/migration.c */
+}
+
int main(void)
{
const struct CMUnitTest tests[] = {
@@ -1232,7 +1380,31 @@ int main(void)
cmocka_unit_test_setup(test_dma_map_sg, setup),
cmocka_unit_test_setup(test_dma_addr_to_sg, setup),
cmocka_unit_test_setup(test_vfu_setup_device_dma_cb, setup),
- cmocka_unit_test_setup(test_migration_state_transitions, setup)
+ cmocka_unit_test_setup(test_migration_state_transitions, setup),
+ cmocka_unit_test_setup_teardown(test_setup_migration_region_too_small,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_region_size_ok,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_region_fully_mappable,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_region_sparsely_mappable_over_migration_registers,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_region_sparsely_mappable_valid,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_callbacks_without_migration_region,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_callbacks_bad_data_offset,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
+ cmocka_unit_test_setup_teardown(test_setup_migration_callbacks,
+ setup_test_setup_migration_region,
+ teardown_test_setup_migration_region),
};
return cmocka_run_group_tests(tests, NULL, NULL);