render / rpms / libvirt

Forked from rpms/libvirt 10 months ago
Clone
a3bc25
From 6f532f2e3615bb573a186cfcfddf8fcc1eec7efd Mon Sep 17 00:00:00 2001
a3bc25
Message-Id: <6f532f2e3615bb573a186cfcfddf8fcc1eec7efd@dist-git>
a3bc25
From: Jiri Denemark <jdenemar@redhat.com>
a3bc25
Date: Tue, 11 Jul 2017 15:53:58 +0200
a3bc25
Subject: [PATCH] qemu: Move qemuProcessReconnect to the end of qemu_process.c
a3bc25
a3bc25
qemuProcessReconnect will need to call additional functions which were
a3bc25
originally defined further in qemu_process.c.
a3bc25
a3bc25
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
a3bc25
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
a3bc25
(cherry picked from commit aad362f93b4451e2f3c98923e5e44c4fe6d26d75)
a3bc25
a3bc25
Conflicts:
a3bc25
	src/qemu/qemu_process.c
a3bc25
a3bc25
https://bugzilla.redhat.com/show_bug.cgi?id=1470582
a3bc25
a3bc25
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
a3bc25
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
a3bc25
---
a3bc25
 src/qemu/qemu_process.c | 645 ++++++++++++++++++++++++------------------------
a3bc25
 1 file changed, 323 insertions(+), 322 deletions(-)
a3bc25
a3bc25
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
a3bc25
index 9df463094e..e6f56dc484 100644
a3bc25
--- a/src/qemu/qemu_process.c
a3bc25
+++ b/src/qemu/qemu_process.c
a3bc25
@@ -3331,328 +3331,6 @@ qemuProcessBuildDestroyHugepagesPath(virQEMUDriverPtr driver,
a3bc25
 }
a3bc25
 
a3bc25
 
a3bc25
-struct qemuProcessReconnectData {
a3bc25
-    virConnectPtr conn;
a3bc25
-    virQEMUDriverPtr driver;
a3bc25
-    virDomainObjPtr obj;
a3bc25
-};
a3bc25
-/*
a3bc25
- * Open an existing VM's monitor, re-detect VCPU threads
a3bc25
- * and re-reserve the security labels in use
a3bc25
- *
a3bc25
- * We own the virConnectPtr we are passed here - whoever started
a3bc25
- * this thread function has increased the reference counter to it
a3bc25
- * so that we now have to close it.
a3bc25
- *
a3bc25
- * This function also inherits a locked and ref'd domain object.
a3bc25
- *
a3bc25
- * This function needs to:
a3bc25
- * 1. Enter job
a3bc25
- * 1. just before monitor reconnect do lightweight MonitorEnter
a3bc25
- *    (increase VM refcount and unlock VM)
a3bc25
- * 2. reconnect to monitor
a3bc25
- * 3. do lightweight MonitorExit (lock VM)
a3bc25
- * 4. continue reconnect process
a3bc25
- * 5. EndJob
a3bc25
- *
a3bc25
- * We can't do normal MonitorEnter & MonitorExit because these two lock the
a3bc25
- * monitor lock, which does not exists in this early phase.
a3bc25
- */
a3bc25
-static void
a3bc25
-qemuProcessReconnect(void *opaque)
a3bc25
-{
a3bc25
-    struct qemuProcessReconnectData *data = opaque;
a3bc25
-    virQEMUDriverPtr driver = data->driver;
a3bc25
-    virDomainObjPtr obj = data->obj;
a3bc25
-    qemuDomainObjPrivatePtr priv;
a3bc25
-    virConnectPtr conn = data->conn;
a3bc25
-    struct qemuDomainJobObj oldjob;
a3bc25
-    int state;
a3bc25
-    int reason;
a3bc25
-    virQEMUDriverConfigPtr cfg;
a3bc25
-    size_t i;
a3bc25
-    unsigned int stopFlags = 0;
a3bc25
-    bool jobStarted = false;
a3bc25
-    virCapsPtr caps = NULL;
a3bc25
-
a3bc25
-    VIR_FREE(data);
a3bc25
-
a3bc25
-    qemuDomainObjRestoreJob(obj, &oldjob);
a3bc25
-    if (oldjob.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN)
a3bc25
-        stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED;
a3bc25
-
a3bc25
-    cfg = virQEMUDriverGetConfig(driver);
a3bc25
-    priv = obj->privateData;
a3bc25
-
a3bc25
-    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuDomainObjBeginJob(driver, obj, QEMU_JOB_MODIFY) < 0)
a3bc25
-        goto error;
a3bc25
-    jobStarted = true;
a3bc25
-
a3bc25
-    /* XXX If we ever gonna change pid file pattern, come up with
a3bc25
-     * some intelligence here to deal with old paths. */
a3bc25
-    if (!(priv->pidfile = virPidFileBuildPath(cfg->stateDir, obj->def->name)))
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    /* Restore the masterKey */
a3bc25
-    if (qemuDomainMasterKeyReadFile(priv) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    virNWFilterReadLockFilterUpdates();
a3bc25
-
a3bc25
-    VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name);
a3bc25
-
a3bc25
-    /* XXX check PID liveliness & EXE path */
a3bc25
-    if (qemuConnectMonitor(driver, obj, QEMU_ASYNC_JOB_NONE, NULL) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuHostdevUpdateActiveDomainDevices(driver, obj->def) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuConnectCgroup(driver, obj) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuDomainPerfRestart(obj) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    /* XXX: Need to change as long as lock is introduced for
a3bc25
-     * qemu_driver->sharedDevices.
a3bc25
-     */
a3bc25
-    for (i = 0; i < obj->def->ndisks; i++) {
a3bc25
-        virDomainDeviceDef dev;
a3bc25
-
a3bc25
-        if (virStorageTranslateDiskSourcePool(conn, obj->def->disks[i]) < 0)
a3bc25
-            goto error;
a3bc25
-
a3bc25
-        /* XXX we should be able to restore all data from XML in the future.
a3bc25
-         * This should be the only place that calls qemuDomainDetermineDiskChain
a3bc25
-         * with @report_broken == false to guarantee best-effort domain
a3bc25
-         * reconnect */
a3bc25
-        if (qemuDomainDetermineDiskChain(driver, obj, obj->def->disks[i],
a3bc25
-                                         true, false) < 0)
a3bc25
-            goto error;
a3bc25
-
a3bc25
-        dev.type = VIR_DOMAIN_DEVICE_DISK;
a3bc25
-        dev.data.disk = obj->def->disks[i];
a3bc25
-        if (qemuAddSharedDevice(driver, &dev, obj->def->name) < 0)
a3bc25
-            goto error;
a3bc25
-    }
a3bc25
-
a3bc25
-    if (qemuProcessUpdateState(driver, obj) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    state = virDomainObjGetState(obj, &reason);
a3bc25
-    if (state == VIR_DOMAIN_SHUTOFF ||
a3bc25
-        (state == VIR_DOMAIN_PAUSED &&
a3bc25
-         reason == VIR_DOMAIN_PAUSED_STARTING_UP)) {
a3bc25
-        VIR_DEBUG("Domain '%s' wasn't fully started yet, killing it",
a3bc25
-                  obj->def->name);
a3bc25
-        goto error;
a3bc25
-    }
a3bc25
-
a3bc25
-    /* If upgrading from old libvirtd we won't have found any
a3bc25
-     * caps in the domain status, so re-query them
a3bc25
-     */
a3bc25
-    if (!priv->qemuCaps &&
a3bc25
-        !(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps,
a3bc25
-                                                      driver->qemuCapsCache,
a3bc25
-                                                      obj->def->emulator,
a3bc25
-                                                      obj->def->os.machine)))
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    /* In case the domain shutdown while we were not running,
a3bc25
-     * we need to finish the shutdown process. And we need to do it after
a3bc25
-     * we have virQEMUCaps filled in.
a3bc25
-     */
a3bc25
-    if (state == VIR_DOMAIN_SHUTDOWN ||
a3bc25
-        (state == VIR_DOMAIN_PAUSED &&
a3bc25
-         reason == VIR_DOMAIN_PAUSED_SHUTTING_DOWN)) {
a3bc25
-        VIR_DEBUG("Finishing shutdown sequence for domain %s",
a3bc25
-                  obj->def->name);
a3bc25
-        qemuProcessShutdownOrReboot(driver, obj);
a3bc25
-        goto cleanup;
a3bc25
-    }
a3bc25
-
a3bc25
-    if (qemuProcessBuildDestroyHugepagesPath(driver, obj, true) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps,
a3bc25
-                                   driver, obj, false)) < 0) {
a3bc25
-        goto error;
a3bc25
-    }
a3bc25
-
a3bc25
-    /* if domain requests security driver we haven't loaded, report error, but
a3bc25
-     * do not kill the domain
a3bc25
-     */
a3bc25
-    ignore_value(qemuSecurityCheckAllLabel(driver->securityManager,
a3bc25
-                                           obj->def));
a3bc25
-
a3bc25
-    if (qemuDomainRefreshVcpuInfo(driver, obj, QEMU_ASYNC_JOB_NONE, true) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    qemuDomainVcpuPersistOrder(obj->def);
a3bc25
-
a3bc25
-    if (qemuSecurityReserveLabel(driver->securityManager, obj->def, obj->pid) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    qemuProcessNotifyNets(obj->def);
a3bc25
-
a3bc25
-    if (qemuProcessFiltersInstantiate(obj->def))
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuProcessRefreshDisks(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuBlockNodeNamesDetect(driver, obj) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    /* If querying of guest's RTC failed, report error, but do not kill the domain. */
a3bc25
-    qemuRefreshRTC(driver, obj);
a3bc25
-
a3bc25
-    if (qemuProcessRefreshBalloonState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuProcessRecoverJob(driver, obj, conn, &oldjob, &stopFlags) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    if (qemuProcessUpdateDevices(driver, obj) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    qemuProcessReconnectCheckMemAliasOrderMismatch(obj);
a3bc25
-
a3bc25
-    if (qemuConnectAgent(driver, obj) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    /* update domain state XML with possibly updated state in virDomainObj */
a3bc25
-    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj, driver->caps) < 0)
a3bc25
-        goto error;
a3bc25
-
a3bc25
-    /* Run an hook to allow admins to do some magic */
a3bc25
-    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
a3bc25
-        char *xml = qemuDomainDefFormatXML(driver, obj->def, 0);
a3bc25
-        int hookret;
a3bc25
-
a3bc25
-        hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, obj->def->name,
a3bc25
-                              VIR_HOOK_QEMU_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN,
a3bc25
-                              NULL, xml, NULL);
a3bc25
-        VIR_FREE(xml);
a3bc25
-
a3bc25
-        /*
a3bc25
-         * If the script raised an error abort the launch
a3bc25
-         */
a3bc25
-        if (hookret < 0)
a3bc25
-            goto error;
a3bc25
-    }
a3bc25
-
a3bc25
-    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
a3bc25
-        driver->inhibitCallback(true, driver->inhibitOpaque);
a3bc25
-
a3bc25
- cleanup:
a3bc25
-    if (jobStarted)
a3bc25
-        qemuDomainObjEndJob(driver, obj);
a3bc25
-    if (!virDomainObjIsActive(obj))
a3bc25
-        qemuDomainRemoveInactive(driver, obj);
a3bc25
-    virDomainObjEndAPI(&obj);
a3bc25
-    virObjectUnref(conn);
a3bc25
-    virObjectUnref(cfg);
a3bc25
-    virObjectUnref(caps);
a3bc25
-    virNWFilterUnlockFilterUpdates();
a3bc25
-    return;
a3bc25
-
a3bc25
- error:
a3bc25
-    if (virDomainObjIsActive(obj)) {
a3bc25
-        /* We can't get the monitor back, so must kill the VM
a3bc25
-         * to remove danger of it ending up running twice if
a3bc25
-         * user tries to start it again later
a3bc25
-         */
a3bc25
-        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
a3bc25
-            /* If we couldn't get the monitor and qemu supports
a3bc25
-             * no-shutdown, we can safely say that the domain
a3bc25
-             * crashed ... */
a3bc25
-            state = VIR_DOMAIN_SHUTOFF_CRASHED;
a3bc25
-        } else {
a3bc25
-            /* ... but if it doesn't we can't say what the state
a3bc25
-             * really is and FAILED means "failed to start" */
a3bc25
-            state = VIR_DOMAIN_SHUTOFF_UNKNOWN;
a3bc25
-        }
a3bc25
-        /* If BeginJob failed, we jumped here without a job, let's hope another
a3bc25
-         * thread didn't have a chance to start playing with the domain yet
a3bc25
-         * (it's all we can do anyway).
a3bc25
-         */
a3bc25
-        qemuProcessStop(driver, obj, state, QEMU_ASYNC_JOB_NONE, stopFlags);
a3bc25
-    }
a3bc25
-    goto cleanup;
a3bc25
-}
a3bc25
-
a3bc25
-static int
a3bc25
-qemuProcessReconnectHelper(virDomainObjPtr obj,
a3bc25
-                           void *opaque)
a3bc25
-{
a3bc25
-    virThread thread;
a3bc25
-    struct qemuProcessReconnectData *src = opaque;
a3bc25
-    struct qemuProcessReconnectData *data;
a3bc25
-
a3bc25
-    /* If the VM was inactive, we don't need to reconnect */
a3bc25
-    if (!obj->pid)
a3bc25
-        return 0;
a3bc25
-
a3bc25
-    if (VIR_ALLOC(data) < 0)
a3bc25
-        return -1;
a3bc25
-
a3bc25
-    memcpy(data, src, sizeof(*data));
a3bc25
-    data->obj = obj;
a3bc25
-
a3bc25
-    /* this lock and reference will be eventually transferred to the thread
a3bc25
-     * that handles the reconnect */
a3bc25
-    virObjectLock(obj);
a3bc25
-    virObjectRef(obj);
a3bc25
-
a3bc25
-    /* Since we close the connection later on, we have to make sure that the
a3bc25
-     * threads we start see a valid connection throughout their lifetime. We
a3bc25
-     * simply increase the reference counter here.
a3bc25
-     */
a3bc25
-    virObjectRef(data->conn);
a3bc25
-
a3bc25
-    if (virThreadCreate(&thread, false, qemuProcessReconnect, data) < 0) {
a3bc25
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
a3bc25
-                       _("Could not create thread. QEMU initialization "
a3bc25
-                         "might be incomplete"));
a3bc25
-        /* We can't spawn a thread and thus connect to monitor. Kill qemu.
a3bc25
-         * It's safe to call qemuProcessStop without a job here since there
a3bc25
-         * is no thread that could be doing anything else with the same domain
a3bc25
-         * object.
a3bc25
-         */
a3bc25
-        qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED,
a3bc25
-                        QEMU_ASYNC_JOB_NONE, 0);
a3bc25
-        qemuDomainRemoveInactive(src->driver, obj);
a3bc25
-
a3bc25
-        virDomainObjEndAPI(&obj);
a3bc25
-        virObjectUnref(data->conn);
a3bc25
-        VIR_FREE(data);
a3bc25
-        return -1;
a3bc25
-    }
a3bc25
-
a3bc25
-    return 0;
a3bc25
-}
a3bc25
-
a3bc25
-/**
a3bc25
- * qemuProcessReconnectAll
a3bc25
- *
a3bc25
- * Try to re-open the resources for live VMs that we care
a3bc25
- * about.
a3bc25
- */
a3bc25
-void
a3bc25
-qemuProcessReconnectAll(virConnectPtr conn, virQEMUDriverPtr driver)
a3bc25
-{
a3bc25
-    struct qemuProcessReconnectData data = {.conn = conn, .driver = driver};
a3bc25
-    virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data);
a3bc25
-}
a3bc25
-
a3bc25
 static int
a3bc25
 qemuProcessVNCAllocatePorts(virQEMUDriverPtr driver,
a3bc25
                             virDomainGraphicsDefPtr graphics,
a3bc25
@@ -6958,3 +6636,326 @@ qemuProcessRefreshDisks(virQEMUDriverPtr driver,
a3bc25
     virHashFree(table);
a3bc25
     return ret;
a3bc25
 }
a3bc25
+
a3bc25
+
a3bc25
+struct qemuProcessReconnectData {
a3bc25
+    virConnectPtr conn;
a3bc25
+    virQEMUDriverPtr driver;
a3bc25
+    virDomainObjPtr obj;
a3bc25
+};
a3bc25
+/*
a3bc25
+ * Open an existing VM's monitor, re-detect VCPU threads
a3bc25
+ * and re-reserve the security labels in use
a3bc25
+ *
a3bc25
+ * We own the virConnectPtr we are passed here - whoever started
a3bc25
+ * this thread function has increased the reference counter to it
a3bc25
+ * so that we now have to close it.
a3bc25
+ *
a3bc25
+ * This function also inherits a locked and ref'd domain object.
a3bc25
+ *
a3bc25
+ * This function needs to:
a3bc25
+ * 1. Enter job
a3bc25
+ * 1. just before monitor reconnect do lightweight MonitorEnter
a3bc25
+ *    (increase VM refcount and unlock VM)
a3bc25
+ * 2. reconnect to monitor
a3bc25
+ * 3. do lightweight MonitorExit (lock VM)
a3bc25
+ * 4. continue reconnect process
a3bc25
+ * 5. EndJob
a3bc25
+ *
a3bc25
+ * We can't do normal MonitorEnter & MonitorExit because these two lock the
a3bc25
+ * monitor lock, which does not exists in this early phase.
a3bc25
+ */
a3bc25
+static void
a3bc25
+qemuProcessReconnect(void *opaque)
a3bc25
+{
a3bc25
+    struct qemuProcessReconnectData *data = opaque;
a3bc25
+    virQEMUDriverPtr driver = data->driver;
a3bc25
+    virDomainObjPtr obj = data->obj;
a3bc25
+    qemuDomainObjPrivatePtr priv;
a3bc25
+    virConnectPtr conn = data->conn;
a3bc25
+    struct qemuDomainJobObj oldjob;
a3bc25
+    int state;
a3bc25
+    int reason;
a3bc25
+    virQEMUDriverConfigPtr cfg;
a3bc25
+    size_t i;
a3bc25
+    unsigned int stopFlags = 0;
a3bc25
+    bool jobStarted = false;
a3bc25
+    virCapsPtr caps = NULL;
a3bc25
+
a3bc25
+    VIR_FREE(data);
a3bc25
+
a3bc25
+    qemuDomainObjRestoreJob(obj, &oldjob);
a3bc25
+    if (oldjob.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN)
a3bc25
+        stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED;
a3bc25
+
a3bc25
+    cfg = virQEMUDriverGetConfig(driver);
a3bc25
+    priv = obj->privateData;
a3bc25
+
a3bc25
+    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuDomainObjBeginJob(driver, obj, QEMU_JOB_MODIFY) < 0)
a3bc25
+        goto error;
a3bc25
+    jobStarted = true;
a3bc25
+
a3bc25
+    /* XXX If we ever gonna change pid file pattern, come up with
a3bc25
+     * some intelligence here to deal with old paths. */
a3bc25
+    if (!(priv->pidfile = virPidFileBuildPath(cfg->stateDir, obj->def->name)))
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    /* Restore the masterKey */
a3bc25
+    if (qemuDomainMasterKeyReadFile(priv) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    virNWFilterReadLockFilterUpdates();
a3bc25
+
a3bc25
+    VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name);
a3bc25
+
a3bc25
+    /* XXX check PID liveliness & EXE path */
a3bc25
+    if (qemuConnectMonitor(driver, obj, QEMU_ASYNC_JOB_NONE, NULL) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuHostdevUpdateActiveDomainDevices(driver, obj->def) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuConnectCgroup(driver, obj) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuDomainPerfRestart(obj) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    /* XXX: Need to change as long as lock is introduced for
a3bc25
+     * qemu_driver->sharedDevices.
a3bc25
+     */
a3bc25
+    for (i = 0; i < obj->def->ndisks; i++) {
a3bc25
+        virDomainDeviceDef dev;
a3bc25
+
a3bc25
+        if (virStorageTranslateDiskSourcePool(conn, obj->def->disks[i]) < 0)
a3bc25
+            goto error;
a3bc25
+
a3bc25
+        /* XXX we should be able to restore all data from XML in the future.
a3bc25
+         * This should be the only place that calls qemuDomainDetermineDiskChain
a3bc25
+         * with @report_broken == false to guarantee best-effort domain
a3bc25
+         * reconnect */
a3bc25
+        if (qemuDomainDetermineDiskChain(driver, obj, obj->def->disks[i],
a3bc25
+                                         true, false) < 0)
a3bc25
+            goto error;
a3bc25
+
a3bc25
+        dev.type = VIR_DOMAIN_DEVICE_DISK;
a3bc25
+        dev.data.disk = obj->def->disks[i];
a3bc25
+        if (qemuAddSharedDevice(driver, &dev, obj->def->name) < 0)
a3bc25
+            goto error;
a3bc25
+    }
a3bc25
+
a3bc25
+    if (qemuProcessUpdateState(driver, obj) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    state = virDomainObjGetState(obj, &reason);
a3bc25
+    if (state == VIR_DOMAIN_SHUTOFF ||
a3bc25
+        (state == VIR_DOMAIN_PAUSED &&
a3bc25
+         reason == VIR_DOMAIN_PAUSED_STARTING_UP)) {
a3bc25
+        VIR_DEBUG("Domain '%s' wasn't fully started yet, killing it",
a3bc25
+                  obj->def->name);
a3bc25
+        goto error;
a3bc25
+    }
a3bc25
+
a3bc25
+    /* If upgrading from old libvirtd we won't have found any
a3bc25
+     * caps in the domain status, so re-query them
a3bc25
+     */
a3bc25
+    if (!priv->qemuCaps &&
a3bc25
+        !(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps,
a3bc25
+                                                      driver->qemuCapsCache,
a3bc25
+                                                      obj->def->emulator,
a3bc25
+                                                      obj->def->os.machine)))
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    /* In case the domain shutdown while we were not running,
a3bc25
+     * we need to finish the shutdown process. And we need to do it after
a3bc25
+     * we have virQEMUCaps filled in.
a3bc25
+     */
a3bc25
+    if (state == VIR_DOMAIN_SHUTDOWN ||
a3bc25
+        (state == VIR_DOMAIN_PAUSED &&
a3bc25
+         reason == VIR_DOMAIN_PAUSED_SHUTTING_DOWN)) {
a3bc25
+        VIR_DEBUG("Finishing shutdown sequence for domain %s",
a3bc25
+                  obj->def->name);
a3bc25
+        qemuProcessShutdownOrReboot(driver, obj);
a3bc25
+        goto cleanup;
a3bc25
+    }
a3bc25
+
a3bc25
+    if (qemuProcessBuildDestroyHugepagesPath(driver, obj, true) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps,
a3bc25
+                                   driver, obj, false)) < 0) {
a3bc25
+        goto error;
a3bc25
+    }
a3bc25
+
a3bc25
+    /* if domain requests security driver we haven't loaded, report error, but
a3bc25
+     * do not kill the domain
a3bc25
+     */
a3bc25
+    ignore_value(qemuSecurityCheckAllLabel(driver->securityManager,
a3bc25
+                                           obj->def));
a3bc25
+
a3bc25
+    if (qemuDomainRefreshVcpuInfo(driver, obj, QEMU_ASYNC_JOB_NONE, true) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    qemuDomainVcpuPersistOrder(obj->def);
a3bc25
+
a3bc25
+    if (qemuSecurityReserveLabel(driver->securityManager, obj->def, obj->pid) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    qemuProcessNotifyNets(obj->def);
a3bc25
+
a3bc25
+    if (qemuProcessFiltersInstantiate(obj->def))
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuProcessRefreshDisks(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuBlockNodeNamesDetect(driver, obj) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    /* If querying of guest's RTC failed, report error, but do not kill the domain. */
a3bc25
+    qemuRefreshRTC(driver, obj);
a3bc25
+
a3bc25
+    if (qemuProcessRefreshBalloonState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuProcessRecoverJob(driver, obj, conn, &oldjob, &stopFlags) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    if (qemuProcessUpdateDevices(driver, obj) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    qemuProcessReconnectCheckMemAliasOrderMismatch(obj);
a3bc25
+
a3bc25
+    if (qemuConnectAgent(driver, obj) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    /* update domain state XML with possibly updated state in virDomainObj */
a3bc25
+    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj, driver->caps) < 0)
a3bc25
+        goto error;
a3bc25
+
a3bc25
+    /* Run an hook to allow admins to do some magic */
a3bc25
+    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
a3bc25
+        char *xml = qemuDomainDefFormatXML(driver, obj->def, 0);
a3bc25
+        int hookret;
a3bc25
+
a3bc25
+        hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, obj->def->name,
a3bc25
+                              VIR_HOOK_QEMU_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN,
a3bc25
+                              NULL, xml, NULL);
a3bc25
+        VIR_FREE(xml);
a3bc25
+
a3bc25
+        /*
a3bc25
+         * If the script raised an error abort the launch
a3bc25
+         */
a3bc25
+        if (hookret < 0)
a3bc25
+            goto error;
a3bc25
+    }
a3bc25
+
a3bc25
+    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
a3bc25
+        driver->inhibitCallback(true, driver->inhibitOpaque);
a3bc25
+
a3bc25
+ cleanup:
a3bc25
+    if (jobStarted)
a3bc25
+        qemuDomainObjEndJob(driver, obj);
a3bc25
+    if (!virDomainObjIsActive(obj))
a3bc25
+        qemuDomainRemoveInactive(driver, obj);
a3bc25
+    virDomainObjEndAPI(&obj);
a3bc25
+    virObjectUnref(conn);
a3bc25
+    virObjectUnref(cfg);
a3bc25
+    virObjectUnref(caps);
a3bc25
+    virNWFilterUnlockFilterUpdates();
a3bc25
+    return;
a3bc25
+
a3bc25
+ error:
a3bc25
+    if (virDomainObjIsActive(obj)) {
a3bc25
+        /* We can't get the monitor back, so must kill the VM
a3bc25
+         * to remove danger of it ending up running twice if
a3bc25
+         * user tries to start it again later
a3bc25
+         */
a3bc25
+        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
a3bc25
+            /* If we couldn't get the monitor and qemu supports
a3bc25
+             * no-shutdown, we can safely say that the domain
a3bc25
+             * crashed ... */
a3bc25
+            state = VIR_DOMAIN_SHUTOFF_CRASHED;
a3bc25
+        } else {
a3bc25
+            /* ... but if it doesn't we can't say what the state
a3bc25
+             * really is and FAILED means "failed to start" */
a3bc25
+            state = VIR_DOMAIN_SHUTOFF_UNKNOWN;
a3bc25
+        }
a3bc25
+        /* If BeginJob failed, we jumped here without a job, let's hope another
a3bc25
+         * thread didn't have a chance to start playing with the domain yet
a3bc25
+         * (it's all we can do anyway).
a3bc25
+         */
a3bc25
+        qemuProcessStop(driver, obj, state, QEMU_ASYNC_JOB_NONE, stopFlags);
a3bc25
+    }
a3bc25
+    goto cleanup;
a3bc25
+}
a3bc25
+
a3bc25
+static int
a3bc25
+qemuProcessReconnectHelper(virDomainObjPtr obj,
a3bc25
+                           void *opaque)
a3bc25
+{
a3bc25
+    virThread thread;
a3bc25
+    struct qemuProcessReconnectData *src = opaque;
a3bc25
+    struct qemuProcessReconnectData *data;
a3bc25
+
a3bc25
+    /* If the VM was inactive, we don't need to reconnect */
a3bc25
+    if (!obj->pid)
a3bc25
+        return 0;
a3bc25
+
a3bc25
+    if (VIR_ALLOC(data) < 0)
a3bc25
+        return -1;
a3bc25
+
a3bc25
+    memcpy(data, src, sizeof(*data));
a3bc25
+    data->obj = obj;
a3bc25
+
a3bc25
+    /* this lock and reference will be eventually transferred to the thread
a3bc25
+     * that handles the reconnect */
a3bc25
+    virObjectLock(obj);
a3bc25
+    virObjectRef(obj);
a3bc25
+
a3bc25
+    /* Since we close the connection later on, we have to make sure that the
a3bc25
+     * threads we start see a valid connection throughout their lifetime. We
a3bc25
+     * simply increase the reference counter here.
a3bc25
+     */
a3bc25
+    virObjectRef(data->conn);
a3bc25
+
a3bc25
+    if (virThreadCreate(&thread, false, qemuProcessReconnect, data) < 0) {
a3bc25
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
a3bc25
+                       _("Could not create thread. QEMU initialization "
a3bc25
+                         "might be incomplete"));
a3bc25
+        /* We can't spawn a thread and thus connect to monitor. Kill qemu.
a3bc25
+         * It's safe to call qemuProcessStop without a job here since there
a3bc25
+         * is no thread that could be doing anything else with the same domain
a3bc25
+         * object.
a3bc25
+         */
a3bc25
+        qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED,
a3bc25
+                        QEMU_ASYNC_JOB_NONE, 0);
a3bc25
+        qemuDomainRemoveInactive(src->driver, obj);
a3bc25
+
a3bc25
+        virDomainObjEndAPI(&obj);
a3bc25
+        virObjectUnref(data->conn);
a3bc25
+        VIR_FREE(data);
a3bc25
+        return -1;
a3bc25
+    }
a3bc25
+
a3bc25
+    return 0;
a3bc25
+}
a3bc25
+
a3bc25
+/**
a3bc25
+ * qemuProcessReconnectAll
a3bc25
+ *
a3bc25
+ * Try to re-open the resources for live VMs that we care
a3bc25
+ * about.
a3bc25
+ */
a3bc25
+void
a3bc25
+qemuProcessReconnectAll(virConnectPtr conn, virQEMUDriverPtr driver)
a3bc25
+{
a3bc25
+    struct qemuProcessReconnectData data = {.conn = conn, .driver = driver};
a3bc25
+    virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data);
a3bc25
+}
a3bc25
-- 
a3bc25
2.13.2
a3bc25