diff options
author | Thanos Makatos <thanos.makatos@nutanix.com> | 2021-02-10 09:08:10 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-10 09:08:10 +0000 |
commit | 365ca96a97740332d3633090d850222d10bc9d70 (patch) | |
tree | bd9885cd57351c05ac12d63ef51a4e4e5b3eef7d /lib/migration.c | |
parent | c5d11659c95c995acb77a71fe03c38b240ca43d9 (diff) | |
download | libvfio-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 'lib/migration.c')
-rw-r--r-- | lib/migration.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/lib/migration.c b/lib/migration.c index 2f532e7..0e1b2a6 100644 --- a/lib/migration.c +++ b/lib/migration.c @@ -51,9 +51,14 @@ enum migr_iter_state { }; struct migration { + /* + * TODO if the user provides an FD then should mmap it and use the migration + * registers in the file + */ struct vfio_device_migration_info info; size_t pgsize; vfu_migration_callbacks_t callbacks; + uint64_t data_offset; /* * This is only for the saving state. The resuming state is simpler so we @@ -120,13 +125,24 @@ vfio_migr_state_transition_is_valid(__u32 from, __u32 to) return migr_states[from].state & (1 << to); } +size_t +vfu_get_migr_register_area_size(void) +{ + return ROUND_UP(sizeof(struct vfio_device_migration_info), + sysconf(_SC_PAGE_SIZE)); +} + +/* + * TODO no need to dynamically allocate memory, we can keep struct migration + * in vfu_ctx_t. + */ struct migration * -init_migration(const vfu_migration_t * const vfu_migr, int *err) +init_migration(const vfu_migration_callbacks_t * callbacks, + uint64_t data_offset, int *err) { struct migration *migr; - *err = 0; - if (vfu_migr->size < sizeof(struct vfio_device_migration_info)) { + if (data_offset < vfu_get_migr_register_area_size()) { *err = EINVAL; return NULL; } @@ -140,14 +156,15 @@ init_migration(const vfu_migration_t * const vfu_migr, int *err) /* * FIXME: incorrect, if the client doesn't give a pgsize value, it means "no * migration support", handle this + * FIXME must be available even if migration callbacks aren't used */ migr->pgsize = sysconf(_SC_PAGESIZE); - - /* FIXME this should be done in vfu_ctx_run or poll */ + /* FIXME this should be done in vfu_ctx_realize */ migr->info.device_state = VFIO_DEVICE_STATE_RUNNING; + migr->data_offset = data_offset; - migr->callbacks = vfu_migr->callbacks; + migr->callbacks = *callbacks; if (migr->callbacks.transition == NULL || migr->callbacks.get_pending_bytes == NULL || migr->callbacks.prepare_data == NULL || @@ -345,7 +362,7 @@ handle_data_offset(vfu_ctx_t *vfu_ctx, struct migration *migr, case VFIO_DEVICE_STATE_RUNNING | VFIO_DEVICE_STATE_SAVING: ret = handle_data_offset_when_saving(vfu_ctx, migr, is_write); if (ret == 0 && !is_write) { - *offset = migr->iter.offset + sizeof(struct vfio_device_migration_info); + *offset = migr->iter.offset + migr->data_offset; } return ret; case VFIO_DEVICE_STATE_RESUMING: @@ -358,7 +375,7 @@ handle_data_offset(vfu_ctx_t *vfu_ctx, struct migration *migr, if (ret < 0) { return ret; } - *offset += sizeof(struct vfio_device_migration_info); + *offset += migr->data_offset; return 0; } /* TODO improve error message */ @@ -496,7 +513,19 @@ migration_region_access(vfu_ctx_t *vfu_ctx, char *buf, size_t count, ret = migration_region_access_registers(vfu_ctx, buf, count, pos, is_write); } else { - pos -= sizeof(struct vfio_device_migration_info); + + if (pos < (loff_t)migr->data_offset) { + /* + * TODO we can simply ignore the access to that part and handle + * any access to the data region properly. + */ + vfu_log(vfu_ctx, LOG_WARNING, + "bad access to dead space %#lx-%#lx in migration region", + pos, pos + count - 1); + return -EINVAL; + } + + pos -= migr->data_offset; if (is_write) { ret = migr->callbacks.write_data(vfu_ctx, buf, count, pos); } else { |