提交 e68f395f 编写于 作者: J Jiri Denemark

qemu: Remember incoming migration errors

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: NJiri Denemark <jdenemar@redhat.com>
上级 9d0a2af6
......@@ -252,6 +252,9 @@ struct _virQEMUDriver {
/* Immutable pointer, self-clocking APIs */
virCloseCallbacksPtr closeCallbacks;
/* Immutable pointer, self-locking APIs */
virHashAtomicPtr migrationErrors;
};
typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
......
......@@ -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);
......@@ -12117,6 +12121,7 @@ qemuDomainMigrateFinish2(virConnectPtr dconn,
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching name '%s'"), dname);
qemuMigrationErrorReport(driver, dname);
goto cleanup;
}
......@@ -12566,11 +12571,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;
}
......@@ -12609,11 +12619,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;
}
......
......@@ -5543,8 +5543,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
......@@ -5570,6 +5572,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;
}
......@@ -6094,3 +6097,57 @@ 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 = virHashAtomicNew(64, qemuMigrationErrorFree);
if (driver->migrationErrors)
return 0;
else
return -1;
}
/**
* This function consumes @err; the caller should consider the @err pointer
* invalid after calling this function.
*/
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 (virHashAtomicUpdate(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 = virHashAtomicSteal(driver->migrationErrors, name)))
return;
VIR_DEBUG("Restoring saved incoming migration error for domain %s: %s",
name, err->message);
virSetError(err);
virFreeError(err);
}
......@@ -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__ */
......@@ -1057,6 +1057,20 @@ qemuMonitorSend(qemuMonitorPtr mon,
}
/**
* This function returns a new virError object; the caller is responsible
* for freeing it.
*/
virErrorPtr
qemuMonitorLastError(qemuMonitorPtr mon)
{
if (mon->lastError.code == VIR_ERR_OK)
return NULL;
return virErrorCopyNew(&mon->lastError);
}
virJSONValuePtr
qemuMonitorGetOptions(qemuMonitorPtr mon)
{
......
......@@ -240,6 +240,8 @@ qemuMonitorPtr qemuMonitorOpenFD(virDomainObjPtr vm,
void qemuMonitorClose(qemuMonitorPtr mon);
virErrorPtr qemuMonitorLastError(qemuMonitorPtr mon);
int qemuMonitorSetCapabilities(qemuMonitorPtr mon);
int qemuMonitorSetLink(qemuMonitorPtr mon,
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册