migration: avoid segmentfault when take a snapshot of a VM which being migrated

During an active background migration, snapshot will trigger a
segmentfault. As snapshot clears the "current_migration" struct
and updates "to_dst_file" before it finds out that there is a
migration task, Migration accesses the null pointer in
"current_migration" struct and qemu crashes eventually.

Signed-off-by: Jia Lina <jialina01@baidu.com>
Signed-off-by: Chai Wen <chaiwen@baidu.com>
Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
Message-Id: <20181026083620.10172-1-jialina01@baidu.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
Jia Lina 2018-10-26 16:36:20 +08:00 committed by Dr. David Alan Gilbert
parent ea3b23e5ff
commit 3d63da16fb
3 changed files with 14 additions and 9 deletions

View File

@ -742,7 +742,7 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
* Return true if we're already in the middle of a migration * Return true if we're already in the middle of a migration
* (i.e. any of the active or setup states) * (i.e. any of the active or setup states)
*/ */
static bool migration_is_setup_or_active(int state) bool migration_is_setup_or_active(int state)
{ {
switch (state) { switch (state) {
case MIGRATION_STATUS_ACTIVE: case MIGRATION_STATUS_ACTIVE:

View File

@ -241,6 +241,8 @@ void migrate_fd_error(MigrationState *s, const Error *error);
void migrate_fd_connect(MigrationState *s, Error *error_in); void migrate_fd_connect(MigrationState *s, Error *error_in);
bool migration_is_setup_or_active(int state);
void migrate_init(MigrationState *s); void migrate_init(MigrationState *s);
bool migration_is_blocked(Error **errp); bool migration_is_blocked(Error **errp);
/* True if outgoing migration has entered postcopy phase */ /* True if outgoing migration has entered postcopy phase */

View File

@ -1327,21 +1327,25 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
MigrationState *ms = migrate_get_current(); MigrationState *ms = migrate_get_current();
MigrationStatus status; MigrationStatus status;
migrate_init(ms); if (migration_is_setup_or_active(ms->state) ||
ms->state == MIGRATION_STATUS_CANCELLING ||
ms->to_dst_file = f; ms->state == MIGRATION_STATUS_COLO) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return -EINVAL;
}
if (migration_is_blocked(errp)) { if (migration_is_blocked(errp)) {
ret = -EINVAL; return -EINVAL;
goto done;
} }
if (migrate_use_block()) { if (migrate_use_block()) {
error_setg(errp, "Block migration and snapshots are incompatible"); error_setg(errp, "Block migration and snapshots are incompatible");
ret = -EINVAL; return -EINVAL;
goto done;
} }
migrate_init(ms);
ms->to_dst_file = f;
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
qemu_savevm_state_header(f); qemu_savevm_state_header(f);
qemu_savevm_state_setup(f); qemu_savevm_state_setup(f);
@ -1363,7 +1367,6 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
error_setg_errno(errp, -ret, "Error while writing VM state"); error_setg_errno(errp, -ret, "Error while writing VM state");
} }
done:
if (ret != 0) { if (ret != 0) {
status = MIGRATION_STATUS_FAILED; status = MIGRATION_STATUS_FAILED;
} else { } else {