From 4b8d6d3898c28ff87f32b59e48e7e73158e786f8 Mon Sep 17 00:00:00 2001 From: Thanos Makatos Date: Tue, 16 Feb 2021 11:37:58 +0000 Subject: support live migration in GPIO sample (#324) * gpio: support live migration Signed-off-by: Thanos Makatos Reviewed-by: John Levon --- samples/gpio-pci-idio-16.c | 87 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/samples/gpio-pci-idio-16.c b/samples/gpio-pci-idio-16.c index 771de3a..62ae031 100644 --- a/samples/gpio-pci-idio-16.c +++ b/samples/gpio-pci-idio-16.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "common.h" #include "libvfio-user.h" @@ -51,14 +52,17 @@ _log(vfu_ctx_t *vfu_ctx UNUSED, UNUSED int level, char const *msg) fprintf(stderr, "gpio: %s\n", msg); } +static int pin; +bool dirty = true; + ssize_t bar2_access(vfu_ctx_t *vfu_ctx UNUSED, char * const buf, size_t count, loff_t offset, const bool is_write) { - static char n; - if (offset == 0 && !is_write) - buf[0] = n++ / 3; + buf[0] = pin++ / 3; + + dirty = true; return count; } @@ -67,6 +71,60 @@ static void _sa_handler(UNUSED int signum) { } +static int +migration_device_state_transition(vfu_ctx_t *vfu_ctx, vfu_migr_state_t state) +{ + vfu_log(vfu_ctx, LOG_DEBUG, "migration: transition to state %d", state); + return 0; +} + +static __u64 +migration_get_pending_bytes(UNUSED vfu_ctx_t *vfu_ctx) +{ + if (dirty) { + return sizeof(pin); + } + return 0; +} + +static int +migration_prepare_data(UNUSED vfu_ctx_t *vfu_ctx, __u64 *offset, __u64 *size) +{ + *offset = 0; + if (size != NULL) { /* null means resuming */ + *size = sizeof(pin); + } + return 0; +} + +static ssize_t +migration_read_data(UNUSED vfu_ctx_t *vfu_ctx, void *buf, __u64 size, + __u64 offset) +{ + assert(offset == 0); + assert(size == sizeof(pin)); + memcpy(buf, &pin, sizeof(pin)); + dirty = false; + return 0; +} + +static int +migration_data_written(UNUSED vfu_ctx_t *vfu_ctx, __u64 count) +{ + assert(count == sizeof(pin)); + return 0; +} + +static ssize_t +migration_write_data(UNUSED vfu_ctx_t *vfu_ctx, void *buf, __u64 size, + __u64 offset) +{ + assert(offset == 0); + assert(size == sizeof(pin)); + memcpy(&pin, buf, sizeof(pin)); + return 0; +} + int main(int argc, char *argv[]) { @@ -75,6 +133,18 @@ main(int argc, char *argv[]) char opt; struct sigaction act = { .sa_handler = _sa_handler }; vfu_ctx_t *vfu_ctx; + size_t migr_regs_size = vfu_get_migr_register_area_size(); + size_t migr_data_size = sysconf(_SC_PAGE_SIZE); + size_t migr_size = migr_regs_size + migr_data_size; + const vfu_migration_callbacks_t migr_callbacks = { + .version = VFU_MIGR_CALLBACKS_VERS, + .transition = &migration_device_state_transition, + .get_pending_bytes = &migration_get_pending_bytes, + .prepare_data = &migration_prepare_data, + .read_data = &migration_read_data, + .data_written = &migration_data_written, + .write_data = &migration_write_data + }; while ((opt = getopt(argc, argv, "v")) != -1) { switch (opt) { @@ -125,6 +195,17 @@ main(int argc, char *argv[]) err(EXIT_FAILURE, "failed to setup region"); } + ret = vfu_setup_region(vfu_ctx, VFU_PCI_DEV_MIGR_REGION_IDX, migr_size, + NULL, VFU_REGION_FLAG_RW, NULL, 0, -1); + if (ret < 0) { + err(EXIT_FAILURE, "failed to setup migration region"); + } + ret = vfu_setup_device_migration_callbacks(vfu_ctx, &migr_callbacks, + migr_regs_size); + if (ret < 0) { + err(EXIT_FAILURE, "failed to setup device migration"); + } + ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_INTX_IRQ, 1); if (ret < 0) { err(EXIT_FAILURE, "failed to setup irq counts"); -- cgit v1.1