render / rpms / libvirt

Forked from rpms/libvirt 10 months ago
Clone
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