|
|
7a3408 |
From c6f6fd0e71ca74d9e553bb059de1809a4c1789dd Mon Sep 17 00:00:00 2001
|
|
|
7a3408 |
Message-Id: <c6f6fd0e71ca74d9e553bb059de1809a4c1789dd@dist-git>
|
|
|
7a3408 |
From: Jiri Denemark <jdenemar@redhat.com>
|
|
|
7a3408 |
Date: Thu, 2 Jul 2015 08:26:48 +0200
|
|
|
7a3408 |
Subject: [PATCH] qemu: Remember incoming migration errors
|
|
|
7a3408 |
|
|
|
7a3408 |
If QEMU fails during incoming migration, the domain disappears including
|
|
|
7a3408 |
a possibly useful error message read from QEMU log file. Let's remember
|
|
|
7a3408 |
the error in virQEMUDriver so that Finish can report more than just "no
|
|
|
7a3408 |
such domain".
|
|
|
7a3408 |
|
|
|
7a3408 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
7a3408 |
(cherry picked from commit e68f395fcbae0267368f9974cc49f582cc83c752)
|
|
|
7a3408 |
|
|
|
7a3408 |
https://bugzilla.redhat.com/show_bug.cgi?id=1090093
|
|
|
7a3408 |
|
|
|
7a3408 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
7a3408 |
---
|
|
|
7a3408 |
src/qemu/qemu_conf.h | 3 +++
|
|
|
7a3408 |
src/qemu/qemu_driver.c | 31 ++++++++++++++++++-------
|
|
|
7a3408 |
src/qemu/qemu_migration.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
7a3408 |
src/qemu/qemu_migration.h | 7 ++++++
|
|
|
7a3408 |
src/qemu/qemu_monitor.c | 14 +++++++++++
|
|
|
7a3408 |
src/qemu/qemu_monitor.h | 2 ++
|
|
|
7a3408 |
src/qemu/qemu_process.c | 4 ++++
|
|
|
7a3408 |
7 files changed, 111 insertions(+), 9 deletions(-)
|
|
|
7a3408 |
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
|
|
|
7a3408 |
index b74c283..3f73929 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_conf.h
|
|
|
7a3408 |
+++ b/src/qemu/qemu_conf.h
|
|
|
7a3408 |
@@ -252,6 +252,9 @@ struct _virQEMUDriver {
|
|
|
7a3408 |
|
|
|
7a3408 |
/* Immutable pointer, self-clocking APIs */
|
|
|
7a3408 |
virCloseCallbacksPtr closeCallbacks;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ /* Immutable pointer, self-locking APIs */
|
|
|
7a3408 |
+ virHashAtomicPtr migrationErrors;
|
|
|
7a3408 |
};
|
|
|
7a3408 |
|
|
|
7a3408 |
typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
7a3408 |
index 063bedb..fb42dae 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_driver.c
|
|
|
7a3408 |
+++ b/src/qemu/qemu_driver.c
|
|
|
7a3408 |
@@ -775,6 +775,9 @@ qemuStateInitialize(bool privileged,
|
|
|
7a3408 |
if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree)))
|
|
|
7a3408 |
goto error;
|
|
|
7a3408 |
|
|
|
7a3408 |
+ if (qemuMigrationErrorInit(qemu_driver) < 0)
|
|
|
7a3408 |
+ goto error;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
if (privileged) {
|
|
|
7a3408 |
char *channeldir;
|
|
|
7a3408 |
|
|
|
7a3408 |
@@ -1091,6 +1094,7 @@ qemuStateCleanup(void)
|
|
|
7a3408 |
virObjectUnref(qemu_driver->remotePorts);
|
|
|
7a3408 |
virObjectUnref(qemu_driver->webSocketPorts);
|
|
|
7a3408 |
virObjectUnref(qemu_driver->migrationPorts);
|
|
|
7a3408 |
+ virObjectUnref(qemu_driver->migrationErrors);
|
|
|
7a3408 |
|
|
|
7a3408 |
virObjectUnref(qemu_driver->xmlopt);
|
|
|
7a3408 |
|
|
|
7a3408 |
@@ -12199,6 +12203,7 @@ qemuDomainMigrateFinish2(virConnectPtr dconn,
|
|
|
7a3408 |
if (!vm) {
|
|
|
7a3408 |
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
7a3408 |
_("no domain with matching name '%s'"), dname);
|
|
|
7a3408 |
+ qemuMigrationErrorReport(driver, dname);
|
|
|
7a3408 |
goto cleanup;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
@@ -12648,11 +12653,16 @@ qemuDomainMigrateFinish3(virConnectPtr dconn,
|
|
|
7a3408 |
|
|
|
7a3408 |
virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
|
|
|
7a3408 |
|
|
|
7a3408 |
- if (!dname ||
|
|
|
7a3408 |
- !(vm = virDomainObjListFindByName(driver->domains, dname))) {
|
|
|
7a3408 |
+ if (!dname) {
|
|
|
7a3408 |
+ virReportError(VIR_ERR_NO_DOMAIN, "%s", _("missing domain name"));
|
|
|
7a3408 |
+ return NULL;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ vm = virDomainObjListFindByName(driver->domains, dname);
|
|
|
7a3408 |
+ if (!vm) {
|
|
|
7a3408 |
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
7a3408 |
- _("no domain with matching name '%s'"),
|
|
|
7a3408 |
- NULLSTR(dname));
|
|
|
7a3408 |
+ _("no domain with matching name '%s'"), dname);
|
|
|
7a3408 |
+ qemuMigrationErrorReport(driver, dname);
|
|
|
7a3408 |
return NULL;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
@@ -12691,11 +12701,16 @@ qemuDomainMigrateFinish3Params(virConnectPtr dconn,
|
|
|
7a3408 |
&dname) < 0)
|
|
|
7a3408 |
return NULL;
|
|
|
7a3408 |
|
|
|
7a3408 |
- if (!dname ||
|
|
|
7a3408 |
- !(vm = virDomainObjListFindByName(driver->domains, dname))) {
|
|
|
7a3408 |
+ if (!dname) {
|
|
|
7a3408 |
+ virReportError(VIR_ERR_NO_DOMAIN, "%s", _("missing domain name"));
|
|
|
7a3408 |
+ return NULL;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ vm = virDomainObjListFindByName(driver->domains, dname);
|
|
|
7a3408 |
+ if (!vm) {
|
|
|
7a3408 |
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
7a3408 |
- _("no domain with matching name '%s'"),
|
|
|
7a3408 |
- NULLSTR(dname));
|
|
|
7a3408 |
+ _("no domain with matching name '%s'"), dname);
|
|
|
7a3408 |
+ qemuMigrationErrorReport(driver, dname);
|
|
|
7a3408 |
return NULL;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
|
|
|
7a3408 |
index 7257182..58874ee 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_migration.c
|
|
|
7a3408 |
+++ b/src/qemu/qemu_migration.c
|
|
|
7a3408 |
@@ -5543,8 +5543,10 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
|
|
|
7a3408 |
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
|
|
7a3408 |
goto cleanup;
|
|
|
7a3408 |
|
|
|
7a3408 |
- if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
|
|
|
7a3408 |
+ if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN)) {
|
|
|
7a3408 |
+ qemuMigrationErrorReport(driver, vm->def->name);
|
|
|
7a3408 |
goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
|
|
|
7a3408 |
qemuMigrationJobStartPhase(driver, vm,
|
|
|
7a3408 |
v3proto ? QEMU_MIGRATION_PHASE_FINISH3
|
|
|
7a3408 |
@@ -5570,6 +5572,7 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
|
|
|
7a3408 |
if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
|
|
|
7a3408 |
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
7a3408 |
_("guest unexpectedly quit"));
|
|
|
7a3408 |
+ qemuMigrationErrorReport(driver, vm->def->name);
|
|
|
7a3408 |
goto endjob;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
@@ -6094,3 +6097,57 @@ qemuMigrationJobFinish(virQEMUDriverPtr driver, virDomainObjPtr vm)
|
|
|
7a3408 |
{
|
|
|
7a3408 |
qemuDomainObjEndAsyncJob(driver, vm);
|
|
|
7a3408 |
}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+static void
|
|
|
7a3408 |
+qemuMigrationErrorFree(void *data,
|
|
|
7a3408 |
+ const void *name ATTRIBUTE_UNUSED)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ virErrorPtr err = data;
|
|
|
7a3408 |
+ virFreeError(err);
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+int
|
|
|
7a3408 |
+qemuMigrationErrorInit(virQEMUDriverPtr driver)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ driver->migrationErrors = virHashAtomicNew(64, qemuMigrationErrorFree);
|
|
|
7a3408 |
+ if (driver->migrationErrors)
|
|
|
7a3408 |
+ return 0;
|
|
|
7a3408 |
+ else
|
|
|
7a3408 |
+ return -1;
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+/**
|
|
|
7a3408 |
+ * This function consumes @err; the caller should consider the @err pointer
|
|
|
7a3408 |
+ * invalid after calling this function.
|
|
|
7a3408 |
+ */
|
|
|
7a3408 |
+void
|
|
|
7a3408 |
+qemuMigrationErrorSave(virQEMUDriverPtr driver,
|
|
|
7a3408 |
+ const char *name,
|
|
|
7a3408 |
+ virErrorPtr err)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ if (!err)
|
|
|
7a3408 |
+ return;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ VIR_DEBUG("Saving incoming migration error for domain %s: %s",
|
|
|
7a3408 |
+ name, err->message);
|
|
|
7a3408 |
+ if (virHashAtomicUpdate(driver->migrationErrors, name, err) < 0) {
|
|
|
7a3408 |
+ VIR_WARN("Failed to save migration error for domain '%s'", name);
|
|
|
7a3408 |
+ virFreeError(err);
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+void
|
|
|
7a3408 |
+qemuMigrationErrorReport(virQEMUDriverPtr driver,
|
|
|
7a3408 |
+ const char *name)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ virErrorPtr err;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (!(err = virHashAtomicSteal(driver->migrationErrors, name)))
|
|
|
7a3408 |
+ return;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ VIR_DEBUG("Restoring saved incoming migration error for domain %s: %s",
|
|
|
7a3408 |
+ name, err->message);
|
|
|
7a3408 |
+ virSetError(err);
|
|
|
7a3408 |
+ virFreeError(err);
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
|
|
|
7a3408 |
index 48c2e8c..fa14274 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_migration.h
|
|
|
7a3408 |
+++ b/src/qemu/qemu_migration.h
|
|
|
7a3408 |
@@ -193,4 +193,11 @@ int qemuMigrationFetchJobStatus(virQEMUDriverPtr driver,
|
|
|
7a3408 |
qemuDomainAsyncJob asyncJob,
|
|
|
7a3408 |
qemuDomainJobInfoPtr jobInfo);
|
|
|
7a3408 |
|
|
|
7a3408 |
+int qemuMigrationErrorInit(virQEMUDriverPtr driver);
|
|
|
7a3408 |
+void qemuMigrationErrorSave(virQEMUDriverPtr driver,
|
|
|
7a3408 |
+ const char *name,
|
|
|
7a3408 |
+ virErrorPtr err);
|
|
|
7a3408 |
+void qemuMigrationErrorReport(virQEMUDriverPtr driver,
|
|
|
7a3408 |
+ const char *name);
|
|
|
7a3408 |
+
|
|
|
7a3408 |
#endif /* __QEMU_MIGRATION_H__ */
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
|
|
|
7a3408 |
index dabe8e2..7545dbb 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_monitor.c
|
|
|
7a3408 |
+++ b/src/qemu/qemu_monitor.c
|
|
|
7a3408 |
@@ -1057,6 +1057,20 @@ qemuMonitorSend(qemuMonitorPtr mon,
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
|
|
|
7a3408 |
+/**
|
|
|
7a3408 |
+ * This function returns a new virError object; the caller is responsible
|
|
|
7a3408 |
+ * for freeing it.
|
|
|
7a3408 |
+ */
|
|
|
7a3408 |
+virErrorPtr
|
|
|
7a3408 |
+qemuMonitorLastError(qemuMonitorPtr mon)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ if (mon->lastError.code == VIR_ERR_OK)
|
|
|
7a3408 |
+ return NULL;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ return virErrorCopyNew(&mon->lastError);
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+
|
|
|
7a3408 |
virJSONValuePtr
|
|
|
7a3408 |
qemuMonitorGetOptions(qemuMonitorPtr mon)
|
|
|
7a3408 |
{
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
|
|
|
7a3408 |
index 2ceba28..8ad3b2b 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_monitor.h
|
|
|
7a3408 |
+++ b/src/qemu/qemu_monitor.h
|
|
|
7a3408 |
@@ -240,6 +240,8 @@ qemuMonitorPtr qemuMonitorOpenFD(virDomainObjPtr vm,
|
|
|
7a3408 |
|
|
|
7a3408 |
void qemuMonitorClose(qemuMonitorPtr mon);
|
|
|
7a3408 |
|
|
|
7a3408 |
+virErrorPtr qemuMonitorLastError(qemuMonitorPtr mon);
|
|
|
7a3408 |
+
|
|
|
7a3408 |
int qemuMonitorSetCapabilities(qemuMonitorPtr mon);
|
|
|
7a3408 |
|
|
|
7a3408 |
int qemuMonitorSetLink(qemuMonitorPtr mon,
|
|
|
7a3408 |
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
|
|
7a3408 |
index c5f467b..91ff5f8 100644
|
|
|
7a3408 |
--- a/src/qemu/qemu_process.c
|
|
|
7a3408 |
+++ b/src/qemu/qemu_process.c
|
|
|
7a3408 |
@@ -310,6 +310,10 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|
|
7a3408 |
auditReason = "failed";
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
+ if (qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
|
|
|
7a3408 |
+ qemuMigrationErrorSave(driver, vm->def->name,
|
|
|
7a3408 |
+ qemuMonitorLastError(priv->mon));
|
|
|
7a3408 |
+
|
|
|
7a3408 |
event = virDomainEventLifecycleNewFromObj(vm,
|
|
|
7a3408 |
VIR_DOMAIN_EVENT_STOPPED,
|
|
|
7a3408 |
eventReason);
|
|
|
7a3408 |
--
|
|
|
7a3408 |
2.4.5
|
|
|
7a3408 |
|