6ae9ed
From 7693fcc1d88c699d9863287f144d6d37b0456100 Mon Sep 17 00:00:00 2001
6ae9ed
Message-Id: <7693fcc1d88c699d9863287f144d6d37b0456100@dist-git>
6ae9ed
From: Peter Krempa <pkrempa@redhat.com>
6ae9ed
Date: Wed, 24 Aug 2016 16:11:40 -0400
6ae9ed
Subject: [PATCH] qemu: hotplug: Add support for VCPU unplug
6ae9ed
6ae9ed
https://bugzilla.redhat.com/show_bug.cgi?id=1224341
6ae9ed
https://bugzilla.redhat.com/show_bug.cgi?id=1097930
6ae9ed
6ae9ed
This patch removes the old vcpu unplug code completely and replaces it
6ae9ed
with the new code using device_del. The old hotplug code basically never
6ae9ed
worked with any recent qemu and thus is useless.
6ae9ed
6ae9ed
As the new code is using device_del all the implications of using it
6ae9ed
are present. Contrary to the device deletion code, the vcpu deletion
6ae9ed
code fails if the unplug request is not executed in time.
6ae9ed
6ae9ed
(cherry picked from commit e3229f6e4461cd1721dc68a32e16ab1718ae716e)
6ae9ed
---
6ae9ed
 src/qemu/qemu_driver.c  |  74 ++++++---------------------------
6ae9ed
 src/qemu/qemu_hotplug.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++
6ae9ed
 src/qemu/qemu_hotplug.h |   7 ++++
6ae9ed
 3 files changed, 128 insertions(+), 61 deletions(-)
6ae9ed
6ae9ed
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
6ae9ed
index 900aacd..1ef8bc4 100644
6ae9ed
--- a/src/qemu/qemu_driver.c
6ae9ed
+++ b/src/qemu/qemu_driver.c
6ae9ed
@@ -4067,11 +4067,15 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
6ae9ed
         goto endjob;
6ae9ed
     }
6ae9ed
 
6ae9ed
-    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
6ae9ed
-        goto endjob;
6ae9ed
+    if (STRPREFIX(devAlias, "vcpu")) {
6ae9ed
+        qemuDomainRemoveVcpuAlias(driver, vm, devAlias);
6ae9ed
+    } else {
6ae9ed
+        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
6ae9ed
+            goto endjob;
6ae9ed
 
6ae9ed
-    if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
6ae9ed
-        goto endjob;
6ae9ed
+        if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
6ae9ed
+            goto endjob;
6ae9ed
+    }
6ae9ed
 
6ae9ed
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
6ae9ed
         VIR_WARN("unable to save domain status after removing device %s",
6ae9ed
@@ -4666,60 +4670,6 @@ qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
6ae9ed
 
6ae9ed
 
6ae9ed
 static int
6ae9ed
-qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
6ae9ed
-                         virDomainObjPtr vm,
6ae9ed
-                         unsigned int vcpu)
6ae9ed
-{
6ae9ed
-    qemuDomainObjPrivatePtr priv = vm->privateData;
6ae9ed
-    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
6ae9ed
-    int ret = -1;
6ae9ed
-    int rc;
6ae9ed
-    int oldvcpus = virDomainDefGetVcpus(vm->def);
6ae9ed
-
6ae9ed
-    if (!vcpuinfo->online) {
6ae9ed
-        virReportError(VIR_ERR_INVALID_ARG,
6ae9ed
-                       _("vCPU '%u' is already offline"), vcpu);
6ae9ed
-        return -1;
6ae9ed
-    }
6ae9ed
-
6ae9ed
-    vcpuinfo->online = false;
6ae9ed
-
6ae9ed
-    qemuDomainObjEnterMonitor(driver, vm);
6ae9ed
-
6ae9ed
-    rc = qemuMonitorSetCPU(priv->mon, vcpu, false);
6ae9ed
-
6ae9ed
-    if (qemuDomainObjExitMonitor(driver, vm) < 0)
6ae9ed
-        goto cleanup;
6ae9ed
-
6ae9ed
-    if (rc < 0) {
6ae9ed
-        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - 1, "update", false);
6ae9ed
-        vcpuinfo->online = true;
6ae9ed
-        goto cleanup;
6ae9ed
-    }
6ae9ed
-
6ae9ed
-    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
6ae9ed
-        goto cleanup;
6ae9ed
-
6ae9ed
-    if (qemuDomainValidateVcpuInfo(vm) < 0) {
6ae9ed
-        /* rollback vcpu count if the setting has failed */
6ae9ed
-        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - 1, "update", false);
6ae9ed
-        vcpuinfo->online = true;
6ae9ed
-        goto cleanup;
6ae9ed
-    }
6ae9ed
-
6ae9ed
-    virDomainAuditVcpu(vm, oldvcpus, oldvcpus - 1, "update", true);
6ae9ed
-
6ae9ed
-    if (virCgroupDelThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, vcpu) < 0)
6ae9ed
-        goto cleanup;
6ae9ed
-
6ae9ed
-    ret = 0;
6ae9ed
-
6ae9ed
- cleanup:
6ae9ed
-    return ret;
6ae9ed
-}
6ae9ed
-
6ae9ed
-
6ae9ed
-static int
6ae9ed
 qemuDomainSetVcpusAgent(virDomainObjPtr vm,
6ae9ed
                         unsigned int nvcpus)
6ae9ed
 {
6ae9ed
@@ -4895,7 +4845,6 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
6ae9ed
                        unsigned int nvcpus)
6ae9ed
 {
6ae9ed
     qemuDomainObjPrivatePtr priv = vm->privateData;
6ae9ed
-    size_t i;
6ae9ed
     virCgroupPtr cgroup_temp = NULL;
6ae9ed
     char *mem_mask = NULL;
6ae9ed
     char *all_nodes_str = NULL;
6ae9ed
@@ -4932,8 +4881,11 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
6ae9ed
                 break;
6ae9ed
         }
6ae9ed
     } else {
6ae9ed
-        for (i = virDomainDefGetVcpus(vm->def) - 1; i >= nvcpus; i--) {
6ae9ed
-            if ((rc = qemuDomainHotplugDelVcpu(driver, vm, i)) < 0)
6ae9ed
+        for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
6ae9ed
+            if (!virBitmapIsBitSet(vcpumap, nextvcpu))
6ae9ed
+                continue;
6ae9ed
+
6ae9ed
+            if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0)
6ae9ed
                 break;
6ae9ed
         }
6ae9ed
     }
6ae9ed
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
6ae9ed
index a1a9bd1..f038be5 100644
6ae9ed
--- a/src/qemu/qemu_hotplug.c
6ae9ed
+++ b/src/qemu/qemu_hotplug.c
6ae9ed
@@ -4346,3 +4346,111 @@ qemuDomainDetachMemoryDevice(virQEMUDriverPtr driver,
6ae9ed
     qemuDomainResetDeviceRemoval(vm);
6ae9ed
     return ret;
6ae9ed
 }
6ae9ed
+
6ae9ed
+
6ae9ed
+static int
6ae9ed
+qemuDomainRemoveVcpu(virQEMUDriverPtr driver,
6ae9ed
+                     virDomainObjPtr vm,
6ae9ed
+                     unsigned int vcpu)
6ae9ed
+{
6ae9ed
+    qemuDomainObjPrivatePtr priv = vm->privateData;
6ae9ed
+    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
6ae9ed
+    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
6ae9ed
+    int oldvcpus = virDomainDefGetVcpus(vm->def);
6ae9ed
+    unsigned int nvcpus = vcpupriv->vcpus;
6ae9ed
+    size_t i;
6ae9ed
+
6ae9ed
+    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
6ae9ed
+        return -1;
6ae9ed
+
6ae9ed
+    /* validation requires us to set the expected state prior to calling it */
6ae9ed
+    for (i = vcpu; i < vcpu + nvcpus; i++) {
6ae9ed
+        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
6ae9ed
+        vcpuinfo->online = false;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    if (qemuDomainValidateVcpuInfo(vm) < 0) {
6ae9ed
+        /* rollback vcpu count if the setting has failed */
6ae9ed
+        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
6ae9ed
+
6ae9ed
+        for (i = vcpu; i < vcpu + nvcpus; i++) {
6ae9ed
+            vcpuinfo = virDomainDefGetVcpu(vm->def, i);
6ae9ed
+            vcpuinfo->online = true;
6ae9ed
+        }
6ae9ed
+        return -1;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", true);
6ae9ed
+
6ae9ed
+    for (i = vcpu; i < vcpu + nvcpus; i++) {
6ae9ed
+        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
6ae9ed
+        if (virCgroupDelThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, i) < 0)
6ae9ed
+            return -1;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    return 0;
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
+void
6ae9ed
+qemuDomainRemoveVcpuAlias(virQEMUDriverPtr driver,
6ae9ed
+                          virDomainObjPtr vm,
6ae9ed
+                          const char *alias)
6ae9ed
+{
6ae9ed
+    virDomainVcpuDefPtr vcpu;
6ae9ed
+    qemuDomainVcpuPrivatePtr vcpupriv;
6ae9ed
+    size_t i;
6ae9ed
+
6ae9ed
+    for (i = 0; i < virDomainDefGetVcpusMax(vm->def); i++) {
6ae9ed
+        vcpu = virDomainDefGetVcpu(vm->def, i);
6ae9ed
+        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
6ae9ed
+
6ae9ed
+        if (STREQ_NULLABLE(alias, vcpupriv->alias)) {
6ae9ed
+            qemuDomainRemoveVcpu(driver, vm, i);
6ae9ed
+            return;
6ae9ed
+        }
6ae9ed
+    }
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
+int
6ae9ed
+qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
6ae9ed
+                         virDomainObjPtr vm,
6ae9ed
+                         unsigned int vcpu)
6ae9ed
+{
6ae9ed
+    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
6ae9ed
+    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
6ae9ed
+    int oldvcpus = virDomainDefGetVcpus(vm->def);
6ae9ed
+    unsigned int nvcpus = vcpupriv->vcpus;
6ae9ed
+    int rc;
6ae9ed
+
6ae9ed
+    if (!vcpupriv->alias) {
6ae9ed
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
6ae9ed
+                       _("vcpu '%u' can't be unplugged"), vcpu);
6ae9ed
+        return -1;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);
6ae9ed
+
6ae9ed
+    qemuDomainObjEnterMonitor(driver, vm);
6ae9ed
+
6ae9ed
+    rc = qemuMonitorDelDevice(qemuDomainGetMonitor(vm), vcpupriv->alias);
6ae9ed
+
6ae9ed
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
6ae9ed
+        return -1;
6ae9ed
+
6ae9ed
+    if (rc < 0) {
6ae9ed
+        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
6ae9ed
+        return -1;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
6ae9ed
+        if (rc == 0)
6ae9ed
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
6ae9ed
+                           _("vcpu unplug request timed out"));
6ae9ed
+
6ae9ed
+        return -1;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    return qemuDomainRemoveVcpu(driver, vm, vcpu);
6ae9ed
+}
6ae9ed
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
6ae9ed
index 165d345..b048cf4 100644
6ae9ed
--- a/src/qemu/qemu_hotplug.h
6ae9ed
+++ b/src/qemu/qemu_hotplug.h
6ae9ed
@@ -105,6 +105,13 @@ int qemuDomainDetachRNGDevice(virQEMUDriverPtr driver,
6ae9ed
                               virDomainObjPtr vm,
6ae9ed
                               virDomainRNGDefPtr rng);
6ae9ed
 
6ae9ed
+int qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
6ae9ed
+                             virDomainObjPtr vm,
6ae9ed
+                             unsigned int vcpu);
6ae9ed
+void qemuDomainRemoveVcpuAlias(virQEMUDriverPtr driver,
6ae9ed
+                               virDomainObjPtr vm,
6ae9ed
+                               const char *alias);
6ae9ed
+
6ae9ed
 int
6ae9ed
 qemuDomainChrInsert(virDomainDefPtr vmdef,
6ae9ed
                     virDomainChrDefPtr chr);
6ae9ed
-- 
6ae9ed
2.10.0
6ae9ed