Blob Blame History Raw
From 7693fcc1d88c699d9863287f144d6d37b0456100 Mon Sep 17 00:00:00 2001
Message-Id: <7693fcc1d88c699d9863287f144d6d37b0456100@dist-git>
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 24 Aug 2016 16:11:40 -0400
Subject: [PATCH] qemu: hotplug: Add support for VCPU unplug

https://bugzilla.redhat.com/show_bug.cgi?id=1224341
https://bugzilla.redhat.com/show_bug.cgi?id=1097930

This patch removes the old vcpu unplug code completely and replaces it
with the new code using device_del. The old hotplug code basically never
worked with any recent qemu and thus is useless.

As the new code is using device_del all the implications of using it
are present. Contrary to the device deletion code, the vcpu deletion
code fails if the unplug request is not executed in time.

(cherry picked from commit e3229f6e4461cd1721dc68a32e16ab1718ae716e)
---
 src/qemu/qemu_driver.c  |  74 ++++++---------------------------
 src/qemu/qemu_hotplug.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_hotplug.h |   7 ++++
 3 files changed, 128 insertions(+), 61 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 900aacd..1ef8bc4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4067,11 +4067,15 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
         goto endjob;
     }
 
-    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
-        goto endjob;
+    if (STRPREFIX(devAlias, "vcpu")) {
+        qemuDomainRemoveVcpuAlias(driver, vm, devAlias);
+    } else {
+        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
+            goto endjob;
 
-    if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
-        goto endjob;
+        if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
+            goto endjob;
+    }
 
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
         VIR_WARN("unable to save domain status after removing device %s",
@@ -4666,60 +4670,6 @@ qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
 
 
 static int
-qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
-                         virDomainObjPtr vm,
-                         unsigned int vcpu)
-{
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
-    int ret = -1;
-    int rc;
-    int oldvcpus = virDomainDefGetVcpus(vm->def);
-
-    if (!vcpuinfo->online) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("vCPU '%u' is already offline"), vcpu);
-        return -1;
-    }
-
-    vcpuinfo->online = false;
-
-    qemuDomainObjEnterMonitor(driver, vm);
-
-    rc = qemuMonitorSetCPU(priv->mon, vcpu, false);
-
-    if (qemuDomainObjExitMonitor(driver, vm) < 0)
-        goto cleanup;
-
-    if (rc < 0) {
-        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - 1, "update", false);
-        vcpuinfo->online = true;
-        goto cleanup;
-    }
-
-    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
-        goto cleanup;
-
-    if (qemuDomainValidateVcpuInfo(vm) < 0) {
-        /* rollback vcpu count if the setting has failed */
-        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - 1, "update", false);
-        vcpuinfo->online = true;
-        goto cleanup;
-    }
-
-    virDomainAuditVcpu(vm, oldvcpus, oldvcpus - 1, "update", true);
-
-    if (virCgroupDelThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, vcpu) < 0)
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    return ret;
-}
-
-
-static int
 qemuDomainSetVcpusAgent(virDomainObjPtr vm,
                         unsigned int nvcpus)
 {
@@ -4895,7 +4845,6 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
                        unsigned int nvcpus)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    size_t i;
     virCgroupPtr cgroup_temp = NULL;
     char *mem_mask = NULL;
     char *all_nodes_str = NULL;
@@ -4932,8 +4881,11 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
                 break;
         }
     } else {
-        for (i = virDomainDefGetVcpus(vm->def) - 1; i >= nvcpus; i--) {
-            if ((rc = qemuDomainHotplugDelVcpu(driver, vm, i)) < 0)
+        for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
+            if (!virBitmapIsBitSet(vcpumap, nextvcpu))
+                continue;
+
+            if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0)
                 break;
         }
     }
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index a1a9bd1..f038be5 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -4346,3 +4346,111 @@ qemuDomainDetachMemoryDevice(virQEMUDriverPtr driver,
     qemuDomainResetDeviceRemoval(vm);
     return ret;
 }
+
+
+static int
+qemuDomainRemoveVcpu(virQEMUDriverPtr driver,
+                     virDomainObjPtr vm,
+                     unsigned int vcpu)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
+    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
+    int oldvcpus = virDomainDefGetVcpus(vm->def);
+    unsigned int nvcpus = vcpupriv->vcpus;
+    size_t i;
+
+    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
+        return -1;
+
+    /* validation requires us to set the expected state prior to calling it */
+    for (i = vcpu; i < vcpu + nvcpus; i++) {
+        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
+        vcpuinfo->online = false;
+    }
+
+    if (qemuDomainValidateVcpuInfo(vm) < 0) {
+        /* rollback vcpu count if the setting has failed */
+        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
+
+        for (i = vcpu; i < vcpu + nvcpus; i++) {
+            vcpuinfo = virDomainDefGetVcpu(vm->def, i);
+            vcpuinfo->online = true;
+        }
+        return -1;
+    }
+
+    virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", true);
+
+    for (i = vcpu; i < vcpu + nvcpus; i++) {
+        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
+        if (virCgroupDelThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, i) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
+void
+qemuDomainRemoveVcpuAlias(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm,
+                          const char *alias)
+{
+    virDomainVcpuDefPtr vcpu;
+    qemuDomainVcpuPrivatePtr vcpupriv;
+    size_t i;
+
+    for (i = 0; i < virDomainDefGetVcpusMax(vm->def); i++) {
+        vcpu = virDomainDefGetVcpu(vm->def, i);
+        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
+
+        if (STREQ_NULLABLE(alias, vcpupriv->alias)) {
+            qemuDomainRemoveVcpu(driver, vm, i);
+            return;
+        }
+    }
+}
+
+
+int
+qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
+                         virDomainObjPtr vm,
+                         unsigned int vcpu)
+{
+    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
+    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
+    int oldvcpus = virDomainDefGetVcpus(vm->def);
+    unsigned int nvcpus = vcpupriv->vcpus;
+    int rc;
+
+    if (!vcpupriv->alias) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                       _("vcpu '%u' can't be unplugged"), vcpu);
+        return -1;
+    }
+
+    qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);
+
+    qemuDomainObjEnterMonitor(driver, vm);
+
+    rc = qemuMonitorDelDevice(qemuDomainGetMonitor(vm), vcpupriv->alias);
+
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
+        return -1;
+
+    if (rc < 0) {
+        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
+        return -1;
+    }
+
+    if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
+        if (rc == 0)
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("vcpu unplug request timed out"));
+
+        return -1;
+    }
+
+    return qemuDomainRemoveVcpu(driver, vm, vcpu);
+}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 165d345..b048cf4 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -105,6 +105,13 @@ int qemuDomainDetachRNGDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainRNGDefPtr rng);
 
+int qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
+                             virDomainObjPtr vm,
+                             unsigned int vcpu);
+void qemuDomainRemoveVcpuAlias(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm,
+                               const char *alias);
+
 int
 qemuDomainChrInsert(virDomainDefPtr vmdef,
                     virDomainChrDefPtr chr);
-- 
2.10.0