If QEMU fails during incoming migration, the domain disappears including a possibly useful error message read from QEMU log file. Let's remember the error in virQEMUDriver so that Finish can report more than just "no such domain". Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> --- src/qemu/qemu_conf.h | 3 +++ src/qemu/qemu_driver.c | 31 +++++++++++++++++++------- src/qemu/qemu_migration.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_migration.h | 7 ++++++ src/qemu/qemu_monitor.c | 19 ++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_process.c | 4 ++++ 7 files changed, 112 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index b74c283..b4881c3 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -252,6 +252,9 @@ struct _virQEMUDriver { /* Immutable pointer, self-clocking APIs */ virCloseCallbacksPtr closeCallbacks; + + /* Immutable pointer, self-locking APIs */ + virHashLockablePtr migrationErrors; }; typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4cfae03..cb5c2e8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -775,6 +775,9 @@ qemuStateInitialize(bool privileged, if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree))) goto error; + if (qemuMigrationErrorInit(qemu_driver) < 0) + goto error; + if (privileged) { char *channeldir; @@ -1091,6 +1094,7 @@ qemuStateCleanup(void) virObjectUnref(qemu_driver->remotePorts); virObjectUnref(qemu_driver->webSocketPorts); virObjectUnref(qemu_driver->migrationPorts); + virObjectUnref(qemu_driver->migrationErrors); virObjectUnref(qemu_driver->xmlopt); @@ -12125,6 +12129,7 @@ qemuDomainMigrateFinish2(virConnectPtr dconn, if (!vm) { virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching name '%s'"), dname); + qemuMigrationErrorReport(driver, dname); goto cleanup; } @@ -12574,11 +12579,16 @@ qemuDomainMigrateFinish3(virConnectPtr dconn, virCheckFlags(QEMU_MIGRATION_FLAGS, NULL); - if (!dname || - !(vm = virDomainObjListFindByName(driver->domains, dname))) { + if (!dname) { + virReportError(VIR_ERR_NO_DOMAIN, "%s", _("missing domain name")); + return NULL; + } + + vm = virDomainObjListFindByName(driver->domains, dname); + if (!vm) { virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching name '%s'"), - NULLSTR(dname)); + _("no domain with matching name '%s'"), dname); + qemuMigrationErrorReport(driver, dname); return NULL; } @@ -12617,11 +12627,16 @@ qemuDomainMigrateFinish3Params(virConnectPtr dconn, &dname) < 0) return NULL; - if (!dname || - !(vm = virDomainObjListFindByName(driver->domains, dname))) { + if (!dname) { + virReportError(VIR_ERR_NO_DOMAIN, "%s", _("missing domain name")); + return NULL; + } + + vm = virDomainObjListFindByName(driver->domains, dname); + if (!vm) { virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching name '%s'"), - NULLSTR(dname)); + _("no domain with matching name '%s'"), dname); + qemuMigrationErrorReport(driver, dname); return NULL; } diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index a57a177..82069a1 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -5500,8 +5500,10 @@ qemuMigrationFinish(virQEMUDriverPtr driver, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; - if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN)) + if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN)) { + qemuMigrationErrorReport(driver, vm->def->name); goto cleanup; + } qemuMigrationJobStartPhase(driver, vm, v3proto ? QEMU_MIGRATION_PHASE_FINISH3 @@ -5527,6 +5529,7 @@ qemuMigrationFinish(virQEMUDriverPtr driver, if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("guest unexpectedly quit")); + qemuMigrationErrorReport(driver, vm->def->name); goto endjob; } @@ -6051,3 +6054,53 @@ qemuMigrationJobFinish(virQEMUDriverPtr driver, virDomainObjPtr vm) { qemuDomainObjEndAsyncJob(driver, vm); } + + +static void +qemuMigrationErrorFree(void *data, + const void *name ATTRIBUTE_UNUSED) +{ + virErrorPtr err = data; + virFreeError(err); +} + +int +qemuMigrationErrorInit(virQEMUDriverPtr driver) +{ + driver->migrationErrors = virHashLockableNew(64, qemuMigrationErrorFree); + if (driver->migrationErrors) + return 0; + else + return -1; +} + +void +qemuMigrationErrorSave(virQEMUDriverPtr driver, + const char *name, + virErrorPtr err) +{ + if (!err) + return; + + VIR_DEBUG("Saving incoming migration error for domain %s: %s", + name, err->message); + if (virHashLockableUpdate(driver->migrationErrors, name, err) < 0) { + VIR_WARN("Failed to save migration error for domain '%s'", name); + virFreeError(err); + } +} + +void +qemuMigrationErrorReport(virQEMUDriverPtr driver, + const char *name) +{ + virErrorPtr err; + + if (!(err = virHashLockableSteal(driver->migrationErrors, name))) + return; + + VIR_DEBUG("Restoring saved incoming migration error for domain %s: %s", + name, err->message); + virSetError(err); + virFreeError(err); +} diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 48c2e8c..fa14274 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -193,4 +193,11 @@ int qemuMigrationFetchJobStatus(virQEMUDriverPtr driver, qemuDomainAsyncJob asyncJob, qemuDomainJobInfoPtr jobInfo); +int qemuMigrationErrorInit(virQEMUDriverPtr driver); +void qemuMigrationErrorSave(virQEMUDriverPtr driver, + const char *name, + virErrorPtr err); +void qemuMigrationErrorReport(virQEMUDriverPtr driver, + const char *name); + #endif /* __QEMU_MIGRATION_H__ */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 896d9fd..9db05c5 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1057,6 +1057,25 @@ qemuMonitorSend(qemuMonitorPtr mon, } +virErrorPtr +qemuMonitorLastError(qemuMonitorPtr mon) +{ + virErrorPtr old; + virErrorPtr err; + + if (mon->lastError.code == VIR_ERR_OK) + return NULL; + + old = virSaveLastError(); + virSetError(&mon->lastError); + err = virSaveLastError(); + virSetError(old); + virFreeError(old); + + return err; +} + + virJSONValuePtr qemuMonitorGetOptions(qemuMonitorPtr mon) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index ec1724f..13791be 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -234,6 +234,8 @@ qemuMonitorPtr qemuMonitorOpenFD(virDomainObjPtr vm, void qemuMonitorClose(qemuMonitorPtr mon); +virErrorPtr qemuMonitorLastError(qemuMonitorPtr mon); + int qemuMonitorSetCapabilities(qemuMonitorPtr mon); int qemuMonitorSetLink(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ee522b9..89a7c48 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -310,6 +310,10 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED, auditReason = "failed"; } + if (qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN)) + qemuMigrationErrorSave(driver, vm->def->name, + qemuMonitorLastError(priv->mon)); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, eventReason); -- 2.4.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list