[PATCH v5] qemu: Implement CPUs check against machine type's cpu-max

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement check whether (maximum) vCPUs doesn't exceed machine
type's cpu-max settings.

Differences between v4 and v5 (this one):
 - Changed type to unsigned int
 - Renamed variable to maxCpus to match previous naming
 - When machines types are parsed from command line set maxCpus = 0 to don't show

Differences between v3 and v4:
 - Rebased to latest libvirt version
 - Capability XML output extended by maxCpus field
 - Extended caps-qemu-kvm.xml test by maxCpus for one of test emulators

On older versions of QEMU the check is disabled.

Signed-off-by: Michal Novotny <minovotn@xxxxxxxxxx>
---
 docs/schemas/capability.rng                  |  5 ++++
 src/conf/capabilities.c                      |  4 +++
 src/conf/capabilities.h                      |  1 +
 src/qemu/qemu_capabilities.c                 | 40 +++++++++++++++++++++++++++-
 src/qemu/qemu_capabilities.h                 |  3 ++-
 src/qemu/qemu_monitor.h                      |  1 +
 src/qemu/qemu_monitor_json.c                 |  6 +++++
 src/qemu/qemu_process.c                      | 21 +++++++++++++++
 tests/capabilityschemadata/caps-qemu-kvm.xml | 16 +++++------
 9 files changed, 87 insertions(+), 10 deletions(-)

diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng
index 106ca73..65c7c72 100644
--- a/docs/schemas/capability.rng
+++ b/docs/schemas/capability.rng
@@ -290,6 +290,11 @@
           <text/>
         </attribute>
       </optional>
+      <optional>
+        <attribute name='maxCpus'>
+          <ref name='unsignedInt'/>
+        </attribute>
+      </optional>
       <text/>
     </element>
   </define>
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
index da92c78..5aeb2ab 100644
--- a/src/conf/capabilities.c
+++ b/src/conf/capabilities.c
@@ -853,6 +853,8 @@ virCapabilitiesFormatXML(virCapsPtr caps)
             virBufferAddLit(&xml, "      <machine");
             if (machine->canonical)
                 virBufferAsprintf(&xml, " canonical='%s'", machine->canonical);
+            if (machine->maxCpus > 0)
+                virBufferAsprintf(&xml, " maxCpus='%d'", machine->maxCpus);
             virBufferAsprintf(&xml, ">%s</machine>\n", machine->name);
         }
 
@@ -871,6 +873,8 @@ virCapabilitiesFormatXML(virCapsPtr caps)
                 virBufferAddLit(&xml, "        <machine");
                 if (machine->canonical)
                     virBufferAsprintf(&xml, " canonical='%s'", machine->canonical);
+                if (machine->maxCpus > 0)
+                    virBufferAsprintf(&xml, " maxCpus='%d'", machine->maxCpus);
                 virBufferAsprintf(&xml, ">%s</machine>\n", machine->name);
             }
             virBufferAddLit(&xml, "      </domain>\n");
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
index abcf6de..6c7efde 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -46,6 +46,7 @@ typedef virCapsGuestMachine *virCapsGuestMachinePtr;
 struct _virCapsGuestMachine {
     char *name;
     char *canonical;
+    unsigned int maxCpus;
 };
 
 typedef struct _virCapsGuestDomainInfo virCapsGuestDomainInfo;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index c4e076a..969b001 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -256,6 +256,7 @@ struct _virQEMUCaps {
     size_t nmachineTypes;
     char **machineTypes;
     char **machineAliases;
+    unsigned int *machineMaxCpus;
 };
 
 struct _virQEMUCapsCache {
@@ -335,6 +336,7 @@ virQEMUCapsSetDefaultMachine(virQEMUCapsPtr qemuCaps,
 {
     char *name = qemuCaps->machineTypes[defIdx];
     char *alias = qemuCaps->machineAliases[defIdx];
+    unsigned int maxCpus = qemuCaps->machineMaxCpus[defIdx];
 
     memmove(qemuCaps->machineTypes + 1,
             qemuCaps->machineTypes,
@@ -342,8 +344,12 @@ virQEMUCapsSetDefaultMachine(virQEMUCapsPtr qemuCaps,
     memmove(qemuCaps->machineAliases + 1,
             qemuCaps->machineAliases,
             sizeof(qemuCaps->machineAliases[0]) * defIdx);
+    memmove(qemuCaps->machineMaxCpus + 1,
+            qemuCaps->machineMaxCpus,
+            sizeof(qemuCaps->machineMaxCpus[0]) * defIdx);
     qemuCaps->machineTypes[0] = name;
     qemuCaps->machineAliases[0] = alias;
+    qemuCaps->machineMaxCpus[0] = maxCpus;
 }
 
 /* Format is:
@@ -390,7 +396,8 @@ virQEMUCapsParseMachineTypesStr(const char *output,
         }
 
         if (VIR_REALLOC_N(qemuCaps->machineTypes, qemuCaps->nmachineTypes + 1) < 0 ||
-            VIR_REALLOC_N(qemuCaps->machineAliases, qemuCaps->nmachineTypes + 1) < 0) {
+            VIR_REALLOC_N(qemuCaps->machineAliases, qemuCaps->nmachineTypes + 1) < 0 ||
+            VIR_REALLOC_N(qemuCaps->machineMaxCpus, qemuCaps->nmachineTypes + 1) < 0) {
             VIR_FREE(name);
             VIR_FREE(canonical);
             virReportOOMError();
@@ -404,6 +411,8 @@ virQEMUCapsParseMachineTypesStr(const char *output,
             qemuCaps->machineTypes[qemuCaps->nmachineTypes-1] = name;
             qemuCaps->machineAliases[qemuCaps->nmachineTypes-1] = NULL;
         }
+        /* When parsing from command line we don't have information about maxCpus */
+        qemuCaps->machineMaxCpus[qemuCaps->nmachineTypes-1] = 0;
     } while ((p = next));
 
 
@@ -1764,11 +1773,14 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
         goto no_memory;
     if (VIR_ALLOC_N(ret->machineAliases, qemuCaps->nmachineTypes) < 0)
         goto no_memory;
+    if (VIR_ALLOC_N(ret->machineMaxCpus, qemuCaps->nmachineTypes) < 0)
+        goto no_memory;
     ret->nmachineTypes = qemuCaps->nmachineTypes;
     for (i = 0; i < qemuCaps->nmachineTypes; i++) {
         if (VIR_STRDUP(ret->machineTypes[i], qemuCaps->machineTypes[i]) < 0 ||
             VIR_STRDUP(ret->machineAliases[i], qemuCaps->machineAliases[i]) < 0)
             goto error;
+        ret->machineMaxCpus[i] = qemuCaps->machineMaxCpus[i];
     }
 
     return ret;
@@ -1792,6 +1804,7 @@ void virQEMUCapsDispose(void *obj)
     }
     VIR_FREE(qemuCaps->machineTypes);
     VIR_FREE(qemuCaps->machineAliases);
+    VIR_FREE(qemuCaps->machineMaxCpus);
 
     for (i = 0; i < qemuCaps->ncpuDefinitions; i++) {
         VIR_FREE(qemuCaps->cpuDefinitions[i]);
@@ -1932,6 +1945,7 @@ int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps,
             if (VIR_STRDUP(mach->name, qemuCaps->machineTypes[i]) < 0)
                 goto error;
         }
+        mach->maxCpus = qemuCaps->machineMaxCpus[i];
         (*machines)[i] = mach;
     }
 
@@ -1966,6 +1980,25 @@ const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps,
 }
 
 
+int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps,
+                                 const char *name)
+{
+    size_t i;
+
+    if (!name)
+        return 0;
+
+    for (i = 0; i < qemuCaps->nmachineTypes; i++) {
+        if (!qemuCaps->machineMaxCpus[i])
+            continue;
+        if (STREQ(qemuCaps->machineTypes[i], name))
+            return qemuCaps->machineMaxCpus[i];
+    }
+
+    return 0;
+}
+
+
 static int
 virQEMUCapsProbeQMPCommands(virQEMUCapsPtr qemuCaps,
                             qemuMonitorPtr mon)
@@ -2083,6 +2116,10 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps,
         virReportOOMError();
         goto cleanup;
     }
+    if (VIR_ALLOC_N(qemuCaps->machineMaxCpus, nmachines) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
 
     for (i = 0; i < nmachines; i++) {
         if (VIR_STRDUP(qemuCaps->machineAliases[i], machines[i]->alias) < 0 ||
@@ -2090,6 +2127,7 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps,
             goto cleanup;
         if (machines[i]->isDefault)
             defIdx = i;
+        qemuCaps->machineMaxCpus[i] = machines[i]->maxCpus;
     }
     qemuCaps->nmachineTypes = nmachines;
 
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 64a4b1d..7088747 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -234,7 +234,8 @@ size_t virQEMUCapsGetMachineTypes(virQEMUCapsPtr qemuCaps,
                                   char ***names);
 const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps,
                                            const char *name);
-
+int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps,
+                                 const char *name);
 int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps,
                                    size_t *nmachines,
                                    virCapsGuestMachinePtr **machines);
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 3d9afa3..86ef635 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -654,6 +654,7 @@ struct _qemuMonitorMachineInfo {
     char *name;
     bool isDefault;
     char *alias;
+    unsigned int maxCpus;
 };
 
 int qemuMonitorGetMachines(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 88a0dc9..c0d7960 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4042,6 +4042,12 @@ int qemuMonitorJSONGetMachines(qemuMonitorPtr mon,
             if (VIR_STRDUP(info->alias, tmp) < 0)
                 goto cleanup;
         }
+        if (virJSONValueObjectHasKey(child, "cpu-max") &&
+            virJSONValueObjectGetNumberUint(child, "cpu-max", &info->maxCpus) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("query-machines reply has malformed 'cpu-max' data"));
+            goto cleanup;
+        }
     }
 
     ret = n;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 5a0f18b..ac5ffcf 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3330,6 +3330,24 @@ error:
 }
 
 
+static bool
+qemuValidateCpuMax(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
+{
+    unsigned int maxCpus;
+
+    maxCpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, def->os.machine);
+    if (!maxCpus)
+        return true;
+
+    if (def->maxvcpus > maxCpus) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       "%s", _("Maximum CPUs greater than specified machine type limit"));
+        return false;
+    }
+
+    return true;
+}
+
 int qemuProcessStart(virConnectPtr conn,
                      virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
@@ -3519,6 +3537,9 @@ int qemuProcessStart(virConnectPtr conn,
                                                       vm->def->emulator)))
         goto cleanup;
 
+    if (!qemuValidateCpuMax(vm->def, priv->qemuCaps))
+        goto cleanup;
+
     if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0)
         goto cleanup;
 
diff --git a/tests/capabilityschemadata/caps-qemu-kvm.xml b/tests/capabilityschemadata/caps-qemu-kvm.xml
index 36c4b49..1fbc22b 100644
--- a/tests/capabilityschemadata/caps-qemu-kvm.xml
+++ b/tests/capabilityschemadata/caps-qemu-kvm.xml
@@ -33,18 +33,18 @@
     <arch name='i686'>
       <wordsize>32</wordsize>
       <emulator>/usr/bin/qemu</emulator>
-      <machine>pc-0.11</machine>
-      <machine canonical='pc-0.11'>pc</machine>
-      <machine>pc-0.10</machine>
-      <machine>isapc</machine>
+      <machine maxCpus='255'>pc-0.11</machine>
+      <machine canonical='pc-0.11' maxCpus='255'>pc</machine>
+      <machine maxCpus='255'>pc-0.10</machine>
+      <machine maxCpus='1'>isapc</machine>
       <domain type='qemu'>
       </domain>
       <domain type='kvm'>
         <emulator>/usr/bin/qemu-kvm</emulator>
-        <machine>pc-0.11</machine>
-        <machine canonical='pc-0.11'>pc</machine>
-        <machine>pc-0.10</machine>
-        <machine>isapc</machine>
+        <machine maxCpus='255'>pc-0.11</machine>
+        <machine canonical='pc-0.11' maxCpus='255'>pc</machine>
+        <machine maxCpus='255'>pc-0.10</machine>
+        <machine maxCpus='1'>isapc</machine>
       </domain>
     </arch>
     <features>
-- 
1.7.11.7

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]