migration: Add .save_prepare() handler to struct SaveVMHandlers

Add a new .save_prepare() handler to struct SaveVMHandlers. This handler
is called early, even before migration starts, and can be used by
devices to perform early checks.

Refactor migrate_init() to be able to return errors and call
.save_prepare() from there.

Suggested-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Avihai Horon <avihaih@nvidia.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
master
Avihai Horon 2023-09-06 18:08:51 +03:00 committed by Cédric Le Goater
parent f543aa222d
commit 08fc4cb517
5 changed files with 48 additions and 4 deletions

View File

@ -20,6 +20,11 @@ typedef struct SaveVMHandlers {
/* This runs inside the iothread lock. */
SaveStateHandler *save_state;
/*
* save_prepare is called early, even before migration starts, and can be
* used to perform early checks.
*/
int (*save_prepare)(void *opaque, Error **errp);
void (*save_cleanup)(void *opaque);
int (*save_live_complete_postcopy)(QEMUFile *f, void *opaque);
int (*save_live_complete_precopy)(QEMUFile *f, void *opaque);

View File

@ -1392,8 +1392,15 @@ bool migration_is_active(MigrationState *s)
s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE);
}
void migrate_init(MigrationState *s)
int migrate_init(MigrationState *s, Error **errp)
{
int ret;
ret = qemu_savevm_state_prepare(errp);
if (ret) {
return ret;
}
/*
* Reinitialise all migration state, except
* parameters/capabilities that the user set, and
@ -1432,6 +1439,8 @@ void migrate_init(MigrationState *s)
memset(&mig_stats, 0, sizeof(mig_stats));
memset(&compression_counters, 0, sizeof(compression_counters));
migration_reset_vfio_bytes_transferred();
return 0;
}
int migrate_add_blocker_internal(Error *reason, Error **errp)
@ -1641,7 +1650,9 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
migrate_set_block_incremental(true);
}
migrate_init(s);
if (migrate_init(s, errp)) {
return false;
}
return true;
}

View File

@ -472,7 +472,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in);
bool migration_is_setup_or_active(int state);
bool migration_is_running(int state);
void migrate_init(MigrationState *s);
int migrate_init(MigrationState *s, Error **errp);
bool migration_is_blocked(Error **errp);
/* True if outgoing migration has entered postcopy phase */
bool migration_in_postcopy(void);

View File

@ -1233,6 +1233,30 @@ bool qemu_savevm_state_guest_unplug_pending(void)
return false;
}
int qemu_savevm_state_prepare(Error **errp)
{
SaveStateEntry *se;
int ret;
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
if (!se->ops || !se->ops->save_prepare) {
continue;
}
if (se->ops->is_active) {
if (!se->ops->is_active(se->opaque)) {
continue;
}
}
ret = se->ops->save_prepare(se->opaque, errp);
if (ret < 0) {
return ret;
}
}
return 0;
}
void qemu_savevm_state_setup(QEMUFile *f)
{
MigrationState *ms = migrate_get_current();
@ -1619,7 +1643,10 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
return -EINVAL;
}
migrate_init(ms);
ret = migrate_init(ms, errp);
if (ret) {
return ret;
}
ms->to_dst_file = f;
qemu_mutex_unlock_iothread();

View File

@ -31,6 +31,7 @@
bool qemu_savevm_state_blocked(Error **errp);
void qemu_savevm_non_migratable_list(strList **reasons);
int qemu_savevm_state_prepare(Error **errp);
void qemu_savevm_state_setup(QEMUFile *f);
bool qemu_savevm_state_guest_unplug_pending(void);
int qemu_savevm_state_resume_prepare(MigrationState *s);