File libvirt-qemu-Implement-support-for-VIR_DOMAIN_VCPU_AGENT-in-qemuDomainSetVcpusFlags.patch of Package libvirt

From 252eab9b1b9675de122bed50ee8b539c70a11c66 Mon Sep 17 00:00:00 2001
Message-Id: <252eab9b1b9675de122bed50ee8b539c70a11c66.1373885147.git.jdenemar@redhat.com>
From: Peter Krempa <pkrempa@redhat.com>
Date: Thu, 13 Jun 2013 15:52:13 +0200
Subject: [PATCH] qemu: Implement support for VIR_DOMAIN_VCPU_AGENT in
 qemuDomainSetVcpusFlags

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

This patch adds support for agent-based cpu disabling and enabling to
qemuDomainSetVcpusFlags() API.
(cherry picked from commit d47eff88fe50e43a36671f6d8d0eeda52835d5e0)

Conflicts:
	src/qemu/qemu_driver.c: only unmatched context
---
 src/qemu/qemu_driver.c | 129 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 116 insertions(+), 13 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d34b462..c793b98 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3919,6 +3919,68 @@ unsupported:
 
 
 static int
+qemuDomainPrepareAgentVCPUs(unsigned int nvcpus,
+                            qemuAgentCPUInfoPtr cpuinfo,
+                            int ncpuinfo)
+{
+    int i;
+    int nonline = 0;
+    int nofflinable = 0;
+
+    /* count the active and offlinable cpus */
+    for (i = 0; i < ncpuinfo; i++) {
+        if (cpuinfo[i].online)
+            nonline++;
+
+        if (cpuinfo[i].offlinable && cpuinfo[i].online)
+            nofflinable++;
+
+        /* This shouldn't happen, but we can't trust the guest agent */
+        if (!cpuinfo[i].online && !cpuinfo[i].offlinable) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Invalid data provided by guest agent"));
+            return -1;
+        }
+    }
+
+    /* the guest agent reported less cpus than requested */
+    if (nvcpus > ncpuinfo) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("guest agent reports less cpu than requested"));
+        return -1;
+    }
+
+    /* not enough offlinable CPUs to support the request */
+    if (nvcpus < nonline - nofflinable) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("Cannot offline enough CPUs"));
+        return -1;
+    }
+
+    for (i = 0; i < ncpuinfo; i++) {
+        if (nvcpus < nonline) {
+            /* unplug */
+            if (cpuinfo[i].offlinable && cpuinfo[i].online) {
+                cpuinfo[i].online = false;
+                nonline--;
+            }
+        } else if (nvcpus > nonline) {
+            /* plug */
+            if (!cpuinfo[i].online) {
+                cpuinfo[i].online = true;
+                nonline++;
+            }
+        } else {
+            /* done */
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+static int
 qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
 {
@@ -3927,10 +3989,14 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     virDomainDefPtr persistentDef;
     int ret = -1;
     bool maximum;
+    qemuAgentCPUInfoPtr cpuinfo = NULL;
+    int ncpuinfo;
+    qemuDomainObjPrivatePtr priv;
 
     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                   VIR_DOMAIN_AFFECT_CONFIG |
-                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
+                  VIR_DOMAIN_VCPU_MAXIMUM |
+                  VIR_DOMAIN_VCPU_AGENT, -1);
 
     if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
         virReportError(VIR_ERR_INVALID_ARG,
@@ -3950,6 +4016,8 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
         goto cleanup;
     }
 
+    priv = vm->privateData;
+
     if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
         goto cleanup;
 
@@ -3975,22 +4043,56 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
         goto endjob;
     }
 
-    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
-        if (qemudDomainHotplugVcpus(driver, vm, nvcpus) < 0)
+    if (flags & VIR_DOMAIN_VCPU_AGENT) {
+        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("chainging of maximum vCPU count isn't supported "
+                             "via guest agent"));
             goto endjob;
-    }
-
-    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
-        if (maximum) {
-            persistentDef->maxvcpus = nvcpus;
-            if (nvcpus < persistentDef->vcpus)
-                persistentDef->vcpus = nvcpus;
-        } else {
-            persistentDef->vcpus = nvcpus;
         }
 
-        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
+        qemuDomainObjEnterAgent(driver, vm);
+        ncpuinfo = qemuAgentGetVCPUs(priv->agent, &cpuinfo);
+        qemuDomainObjExitAgent(driver, vm);
+
+        if (ncpuinfo < 0)
+            goto endjob;
+
+        if (qemuDomainPrepareAgentVCPUs(nvcpus, cpuinfo, ncpuinfo) < 0)
+            goto endjob;
+
+        qemuDomainObjEnterAgent(driver, vm);
+        ret = qemuAgentSetVCPUs(priv->agent, cpuinfo, ncpuinfo);
+        qemuDomainObjExitAgent(driver, vm);
+
+        if (ret < 0)
+            goto endjob;
+
+        if (ret < ncpuinfo) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("failed to set state of cpu %d via guest agent"),
+                           cpuinfo[ret-1].id);
+            ret = -1;
             goto endjob;
+        }
+    } else {
+        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+            if (qemudDomainHotplugVcpus(driver, vm, nvcpus) < 0)
+                goto endjob;
+        }
+
+        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+            if (maximum) {
+                persistentDef->maxvcpus = nvcpus;
+                if (nvcpus < persistentDef->vcpus)
+                    persistentDef->vcpus = nvcpus;
+            } else {
+                persistentDef->vcpus = nvcpus;
+            }
+
+            if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
+                goto endjob;
+        }
     }
 
     ret = 0;
@@ -4002,6 +4104,7 @@ endjob:
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    VIR_FREE(cpuinfo);
     return ret;
 }
 
-- 
1.8.3.2

openSUSE Build Service is sponsored by