]> xenbits.xensource.com Git - libvirt.git/commitdiff
numatune: Encapsulate numatune configuration in order to unify results
authorMartin Kletzander <mkletzan@redhat.com>
Mon, 9 Jun 2014 13:00:22 +0000 (15:00 +0200)
committerMartin Kletzander <mkletzan@redhat.com>
Wed, 16 Jul 2014 18:15:45 +0000 (20:15 +0200)
There were numerous places where numatune configuration (and thus
domain config as well) was changed in different ways.  On some
places this even resulted in persistent domain definition not to be
stable (it would change with daemon's restart).

In order to uniformly change how numatune config is dealt with, all
the internals are now accessible directly only in numatune_conf.c and
outside this file accessors must be used.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
18 files changed:
po/POTFILES.in
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/numatune_conf.c
src/conf/numatune_conf.h
src/libvirt_private.syms
src/lxc/lxc_cgroup.c
src/lxc/lxc_controller.c
src/lxc/lxc_native.c
src/parallels/parallels_driver.c
src/qemu/qemu_cgroup.c
src/qemu/qemu_driver.c
src/qemu/qemu_process.c
src/util/virnuma.c
src/util/virnuma.h
tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml [new file with mode: 0644]
tests/qemuxml2xmloutdata/qemuxml2xmlout-numatune-auto-prefer.xml [new file with mode: 0644]
tests/qemuxml2xmltest.c

index fd4b56ec08c4c2d875c21ff314114783561e2e14..d10e892a309ee5a460e9deca776058db7f0ad8d4 100644 (file)
@@ -25,6 +25,7 @@ src/conf/netdev_vlan_conf.c
 src/conf/netdev_vport_profile_conf.c
 src/conf/network_conf.c
 src/conf/node_device_conf.c
+src/conf/numatune_conf.c
 src/conf/nwfilter_conf.c
 src/conf/nwfilter_params.c
 src/conf/object_event.c
index d3d1820aecc0e1bcfd63be5365d96128411bcd3c..a1ef374ad52def747d986676c9be268409e8ea82 100644 (file)
@@ -2102,7 +2102,7 @@ void virDomainDefFree(virDomainDefPtr def)
 
     virDomainVcpuPinDefFree(def->cputune.emulatorpin);
 
-    virBitmapFree(def->numatune.memory.nodemask);
+    virDomainNumatuneFree(def->numatune);
 
     virSysinfoDefFree(def->sysinfo);
 
@@ -11332,7 +11332,6 @@ virDomainDefParseXML(xmlDocPtr xml,
     unsigned long count;
     bool uuid_generated = false;
     virHashTablePtr bootHash = NULL;
-    xmlNodePtr cur;
     bool usb_none = false;
     bool usb_other = false;
     bool usb_master = false;
@@ -11794,123 +11793,8 @@ virDomainDefParseXML(xmlDocPtr xml,
         }
     }
 
-    /* Extract numatune if exists. */
-    if ((n = virXPathNodeSet("./numatune", ctxt, &nodes)) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("cannot extract numatune nodes"));
+    if (virDomainNumatuneParseXML(def, ctxt) < 0)
         goto error;
-    }
-
-    if (n > 1) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("only one numatune is supported"));
-        VIR_FREE(nodes);
-        goto error;
-    }
-
-    if (n) {
-        cur = nodes[0]->children;
-        while (cur != NULL) {
-            if (cur->type == XML_ELEMENT_NODE) {
-                if (xmlStrEqual(cur->name, BAD_CAST "memory")) {
-                    char *mode = NULL;
-                    char *placement = NULL;
-                    char *nodeset = NULL;
-
-                    mode = virXMLPropString(cur, "mode");
-                    if (mode) {
-                        if ((def->numatune.memory.mode =
-                             virDomainNumatuneMemModeTypeFromString(mode)) < 0) {
-                            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                           _("Unsupported NUMA memory "
-                                             "tuning mode '%s'"),
-                                           mode);
-                            VIR_FREE(mode);
-                            goto error;
-                        }
-                        VIR_FREE(mode);
-                    } else {
-                        def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
-                    }
-
-                    nodeset = virXMLPropString(cur, "nodeset");
-                    if (nodeset) {
-                        if (virBitmapParse(nodeset,
-                                           0,
-                                           &def->numatune.memory.nodemask,
-                                           VIR_DOMAIN_CPUMASK_LEN) < 0) {
-                            VIR_FREE(nodeset);
-                            goto error;
-                        }
-                        VIR_FREE(nodeset);
-                    }
-
-                    placement = virXMLPropString(cur, "placement");
-                    int placement_mode = 0;
-                    if (placement) {
-                        if ((placement_mode =
-                             virDomainNumatunePlacementTypeFromString(placement)) < 0) {
-                            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                           _("Unsupported memory placement "
-                                             "mode '%s'"), placement);
-                            VIR_FREE(placement);
-                            goto error;
-                        }
-                        VIR_FREE(placement);
-                    } else if (def->numatune.memory.nodemask) {
-                        /* Defaults to "static" if nodeset is specified. */
-                        placement_mode = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
-                    } else {
-                        /* Defaults to "placement" of <vcpu> if nodeset is
-                         * not specified.
-                         */
-                        if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC)
-                            placement_mode = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
-                        else
-                            placement_mode = VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO;
-                    }
-
-                    if (placement_mode == VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC &&
-                        !def->numatune.memory.nodemask) {
-                        virReportError(VIR_ERR_XML_ERROR, "%s",
-                                       _("nodeset for NUMA memory tuning must be set "
-                                         "if 'placement' is 'static'"));
-                        goto error;
-                    }
-
-                    /* Ignore 'nodeset' if 'placement' is 'auto' finally */
-                    if (placement_mode == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO) {
-                        virBitmapFree(def->numatune.memory.nodemask);
-                        def->numatune.memory.nodemask = NULL;
-                    }
-
-                    /* Copy 'placement' of <numatune> to <vcpu> if its 'placement'
-                     * is not specified and 'placement' of <numatune> is specified.
-                     */
-                    if (placement_mode == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO &&
-                        !def->cpumask)
-                        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;
-
-                    def->numatune.memory.placement_mode = placement_mode;
-                } else {
-                    virReportError(VIR_ERR_XML_ERROR,
-                                   _("unsupported XML element %s"),
-                                   (const char *)cur->name);
-                    goto error;
-                }
-            }
-            cur = cur->next;
-        }
-    } else {
-        /* Defaults NUMA memory placement mode to 'auto' if no <numatune>
-         * and 'placement' of <vcpu> is 'auto'.
-         */
-        if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
-            def->numatune.memory.placement_mode = VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO;
-            def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
-        }
-    }
-    VIR_FREE(nodes);
 
     if ((n = virXPathNodeSet("./resource", ctxt, &nodes)) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -17527,30 +17411,8 @@ virDomainDefFormatInternal(virDomainDefPtr def,
         def->cputune.emulator_period || def->cputune.emulator_quota)
         virBufferAddLit(buf, "</cputune>\n");
 
-    if (def->numatune.memory.nodemask ||
-        def->numatune.memory.placement_mode) {
-        const char *mode;
-        char *nodemask = NULL;
-        const char *placement;
-
-        virBufferAddLit(buf, "<numatune>\n");
-        virBufferAdjustIndent(buf, 2);
-        mode = virDomainNumatuneMemModeTypeToString(def->numatune.memory.mode);
-        virBufferAsprintf(buf, "<memory mode='%s' ", mode);
-
-        if (def->numatune.memory.placement_mode ==
-            VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC) {
-            if (!(nodemask = virBitmapFormat(def->numatune.memory.nodemask)))
-                goto error;
-            virBufferAsprintf(buf, "nodeset='%s'/>\n", nodemask);
-            VIR_FREE(nodemask);
-        } else if (def->numatune.memory.placement_mode) {
-            placement = virDomainNumatunePlacementTypeToString(def->numatune.memory.placement_mode);
-            virBufferAsprintf(buf, "placement='%s'/>\n", placement);
-        }
-        virBufferAdjustIndent(buf, -2);
-        virBufferAddLit(buf, "</numatune>\n");
-    }
+    if (virDomainNumatuneFormatXML(buf, def->numatune) < 0)
+        goto error;
 
     if (def->resource)
         virDomainResourceDefFormat(buf, def->resource);
@@ -19847,3 +19709,16 @@ virDomainObjSetMetadata(virDomainObjPtr vm,
 
     return 0;
 }
+
+
+bool
+virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
+{
+    if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)
+        return true;
+
+    if (virDomainNumatuneHasPlacementAuto(def->numatune))
+        return true;
+
+    return false;
+}
index 6ed2165d0f5155fb57f072f730bae4de099d156d..4c9b7e840ec4581bd15f4a92def37068b1fe57d1 100644 (file)
@@ -67,6 +67,9 @@ typedef virDomainFSDef *virDomainFSDefPtr;
 typedef struct _virDomainNetDef virDomainNetDef;
 typedef virDomainNetDef *virDomainNetDefPtr;
 
+typedef struct _virDomainNumatune virDomainNumatune;
+typedef virDomainNumatune *virDomainNumatunePtr;
+
 typedef struct _virDomainInputDef virDomainInputDef;
 typedef virDomainInputDef *virDomainInputDefPtr;
 
@@ -1897,7 +1900,7 @@ struct _virDomainDef {
         virDomainVcpuPinDefPtr emulatorpin;
     } cputune;
 
-    virDomainNumatune numatune;
+    virDomainNumatunePtr numatune;
     virDomainResourceDefPtr resource;
     virDomainIdMapDef idmap;
 
@@ -2717,4 +2720,7 @@ int virDomainObjSetMetadata(virDomainObjPtr vm,
                             const char *configDir,
                             unsigned int flags);
 
+bool virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
+    ATTRIBUTE_NONNULL(1);
+
 #endif /* __DOMAIN_CONF_H */
index 14300f0d28b6cc8f24322adbd0762a92d1613571..6ce1e2d5e325ceff62722d3fa64f74a4178ab270 100644 (file)
 
 #include "numatune_conf.h"
 
+#include "domain_conf.h"
+#include "viralloc.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_DOMAIN
+
 VIR_ENUM_IMPL(virDomainNumatuneMemMode,
               VIR_DOMAIN_NUMATUNE_MEM_LAST,
               "strict",
@@ -35,3 +41,315 @@ VIR_ENUM_IMPL(virDomainNumatunePlacement,
               "default",
               "static",
               "auto");
+
+struct _virDomainNumatune {
+    struct {
+        virBitmapPtr nodeset;
+        virDomainNumatuneMemMode mode;
+        virDomainNumatunePlacement placement;
+    } memory;               /* pinning for all the memory */
+
+    /* Future NUMA tuning related stuff should go here. */
+};
+
+
+int
+virDomainNumatuneParseXML(virDomainDefPtr def,
+                          xmlXPathContextPtr ctxt)
+{
+    char *tmp = NULL;
+    int mode = -1;
+    int n = 0;
+    int placement = -1;
+    int ret = -1;
+    virBitmapPtr nodeset = NULL;
+    xmlNodePtr node = NULL;
+
+    if (virXPathInt("count(./numatune)", ctxt, &n) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot extract numatune nodes"));
+        goto cleanup;
+    } else if (n > 1) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("only one numatune is supported"));
+        goto cleanup;
+    }
+
+    node = virXPathNode("./numatune/memory[1]", ctxt);
+
+    if (def->numatune) {
+        virDomainNumatuneFree(def->numatune);
+        def->numatune = NULL;
+    }
+
+    if (!node && def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)
+        return 0;
+
+    if (!node) {
+        /* We know that def->placement_mode is "auto" if we're here */
+        if (virDomainNumatuneSet(def, VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO,
+                                 -1, NULL) < 0)
+            goto cleanup;
+        return 0;
+    }
+
+    tmp = virXMLPropString(node, "mode");
+    if (tmp) {
+        mode = virDomainNumatuneMemModeTypeFromString(tmp);
+        if (mode < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Unsupported NUMA memory tuning mode '%s'"),
+                           tmp);
+            goto cleanup;
+        }
+    }
+    VIR_FREE(tmp);
+
+    tmp = virXMLPropString(node, "placement");
+    if (tmp) {
+        placement = virDomainNumatunePlacementTypeFromString(tmp);
+        if (placement < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Unsupported NUMA memory placement mode '%s'"),
+                           tmp);
+            goto cleanup;
+        }
+    }
+    VIR_FREE(tmp);
+
+    tmp = virXMLPropString(node, "nodeset");
+    if (tmp && virBitmapParse(tmp, 0, &nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0)
+        goto cleanup;
+    VIR_FREE(tmp);
+
+    if (virDomainNumatuneSet(def, placement, mode, nodeset) < 0)
+        goto cleanup;
+
+    if (!n) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    virBitmapFree(nodeset);
+    VIR_FREE(tmp);
+    return ret;
+}
+
+int
+virDomainNumatuneFormatXML(virBufferPtr buf,
+                           virDomainNumatunePtr numatune)
+{
+    const char *tmp = NULL;
+    char *nodeset = NULL;
+
+    if (!numatune)
+        return 0;
+
+    virBufferAddLit(buf, "<numatune>\n");
+    virBufferAdjustIndent(buf, 2);
+
+    tmp = virDomainNumatuneMemModeTypeToString(numatune->memory.mode);
+    virBufferAsprintf(buf, "<memory mode='%s' ", tmp);
+
+    if (numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC) {
+        if (!(nodeset = virBitmapFormat(numatune->memory.nodeset)))
+            return -1;
+        virBufferAsprintf(buf, "nodeset='%s'/>\n", nodeset);
+        VIR_FREE(nodeset);
+    } else if (numatune->memory.placement) {
+        tmp = virDomainNumatunePlacementTypeToString(numatune->memory.placement);
+        virBufferAsprintf(buf, "placement='%s'/>\n", tmp);
+    }
+
+    virBufferAdjustIndent(buf, -2);
+    virBufferAddLit(buf, "</numatune>\n");
+    return 0;
+}
+
+void
+virDomainNumatuneFree(virDomainNumatunePtr numatune)
+{
+    if (!numatune)
+        return;
+
+    virBitmapFree(numatune->memory.nodeset);
+
+    VIR_FREE(numatune);
+}
+
+virDomainNumatuneMemMode
+virDomainNumatuneGetMode(virDomainNumatunePtr numatune)
+{
+    return numatune ? numatune->memory.mode : 0;
+}
+
+virBitmapPtr
+virDomainNumatuneGetNodeset(virDomainNumatunePtr numatune,
+                            virBitmapPtr auto_nodeset)
+{
+    if (!numatune)
+        return NULL;
+
+    if (numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)
+        return auto_nodeset;
+
+    /*
+     * This weird logic has the same meaning as switch with
+     * auto/static/default, but can be more readably changed later.
+     */
+    if (numatune->memory.placement != VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC)
+        return NULL;
+
+    return numatune->memory.nodeset;
+}
+
+char *
+virDomainNumatuneFormatNodeset(virDomainNumatunePtr numatune,
+                               virBitmapPtr auto_nodeset)
+{
+    return virBitmapFormat(virDomainNumatuneGetNodeset(numatune,
+                                                       auto_nodeset));
+}
+
+int
+virDomainNumatuneMaybeFormatNodeset(virDomainNumatunePtr numatune,
+                                    virBitmapPtr auto_nodeset,
+                                    char **mask)
+{
+    *mask = NULL;
+
+    if (!numatune)
+        return 0;
+
+    if (numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO &&
+        !auto_nodeset) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Advice from numad is needed in case of "
+                         "automatic numa placement"));
+        return -1;
+    }
+
+    *mask = virDomainNumatuneFormatNodeset(numatune, auto_nodeset);
+    if (!*mask)
+        return -1;
+
+    return 0;
+}
+
+int
+virDomainNumatuneSet(virDomainDefPtr def,
+                     int placement,
+                     int mode,
+                     virBitmapPtr nodeset)
+{
+    bool create = !def->numatune;  /* Whether we are creating new struct */
+    int ret = -1;
+    virDomainNumatunePtr numatune = NULL;
+
+    /* No need to do anything in this case */
+    if (mode == -1 && placement == -1 && !nodeset)
+        return 0;
+
+    /* Range checks */
+    if (mode != -1 &&
+        (mode < 0 || mode >= VIR_DOMAIN_NUMATUNE_MEM_LAST)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Unsupported numatune mode '%d'"),
+                       mode);
+        goto cleanup;
+    }
+    if (placement != -1 &&
+        (placement < 0 || placement >= VIR_DOMAIN_NUMATUNE_PLACEMENT_LAST)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Unsupported numatune placement '%d'"),
+                       mode);
+        goto cleanup;
+    }
+
+    if (create && VIR_ALLOC(def->numatune) < 0)
+        goto cleanup;
+    numatune = def->numatune;
+
+    if (create) {
+        /* Defaults for new struct */
+        if (mode == -1)
+            mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
+
+        if (placement == -1)
+            placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT;
+    }
+
+    if (mode != -1)
+        numatune->memory.mode = mode;
+    if (nodeset) {
+        virBitmapFree(numatune->memory.nodeset);
+        numatune->memory.nodeset = virBitmapNewCopy(nodeset);
+        if (!numatune->memory.nodeset)
+            goto cleanup;
+        if (placement == -1)
+            placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
+    }
+
+    if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT) {
+        if (numatune->memory.nodeset ||
+            def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC)
+            placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
+        else
+            placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO;
+    }
+
+    if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC &&
+        !numatune->memory.nodeset) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("nodeset for NUMA memory tuning must be set "
+                         "if 'placement' is 'static'"));
+        goto cleanup;
+    }
+
+    if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO) {
+        virBitmapFree(numatune->memory.nodeset);
+        numatune->memory.nodeset = NULL;
+        if (!def->cpumask)
+            def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;
+    }
+
+    if (placement != -1)
+        numatune->memory.placement = placement;
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+bool
+virDomainNumatuneEquals(virDomainNumatunePtr n1,
+                        virDomainNumatunePtr n2)
+{
+    if (!n1 && !n2)
+        return true;
+
+    if (!n1 || !n2)
+        return false;
+
+    if (n1->memory.mode != n2->memory.mode)
+        return false;
+
+    if (n1->memory.placement != n2->memory.placement)
+        return false;
+
+    return virBitmapEqual(n1->memory.nodeset, n2->memory.nodeset);
+}
+
+bool
+virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune)
+{
+    if (!numatune)
+        return false;
+
+    if (numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)
+        return true;
+
+    return false;
+}
index baac7bf7d04b3ae624dfa2820f3e8b3e9c39c3f2..888cff1bf462629f828ec2294dfc9383d3fd0b36 100644 (file)
 #ifndef __NUMATUNE_CONF_H__
 # define __NUMATUNE_CONF_H__
 
+# include <libxml/xpath.h>
+
 # include "internal.h"
 # include "virutil.h"
 # include "virbitmap.h"
+# include "virbuffer.h"
+
+/*
+ * Since numatune configuration is closely bound to the whole config,
+ * and because we don't have separate domain_conf headers for
+ * typedefs, structs and functions, we need to have a forward
+ * declaration here for virDomainDef due to circular dependencies.
+ */
+typedef struct _virDomainDef virDomainDef;
+typedef virDomainDef *virDomainDefPtr;
+
+
+typedef struct _virDomainNumatune virDomainNumatune;
+typedef virDomainNumatune *virDomainNumatunePtr;
 
 typedef enum {
     VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT = 0,
@@ -36,19 +52,51 @@ typedef enum {
 } virDomainNumatunePlacement;
 
 VIR_ENUM_DECL(virDomainNumatunePlacement)
-
 VIR_ENUM_DECL(virDomainNumatuneMemMode)
 
-typedef struct _virDomainNumatune virDomainNumatune;
-typedef virDomainNumatune *virDomainNumatunePtr;
-struct _virDomainNumatune {
-    struct {
-        virBitmapPtr nodemask;
-        int mode;           /* enum virDomainNumatuneMemMode */
-        int placement_mode; /* enum virDomainNumatunePlacement */
-    } memory;               /* pinning for all the memory */
-
-    /* Future NUMA tuning related stuff should go here. */
-};
+
+void virDomainNumatuneFree(virDomainNumatunePtr numatune);
+
+/*
+ * XML Parse/Format functions
+ */
+int virDomainNumatuneParseXML(virDomainDefPtr def, xmlXPathContextPtr ctxt)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int virDomainNumatuneFormatXML(virBufferPtr buf, virDomainNumatunePtr numatune)
+    ATTRIBUTE_NONNULL(1);
+
+/*
+ * Getters
+ */
+virDomainNumatuneMemMode virDomainNumatuneGetMode(virDomainNumatunePtr numatune);
+
+virBitmapPtr virDomainNumatuneGetNodeset(virDomainNumatunePtr numatune,
+                                         virBitmapPtr auto_nodeset);
+
+/*
+ * Formatters
+ */
+char *virDomainNumatuneFormatNodeset(virDomainNumatunePtr numatune,
+                                     virBitmapPtr auto_nodeset);
+
+int virDomainNumatuneMaybeFormatNodeset(virDomainNumatunePtr numatune,
+                                        virBitmapPtr auto_nodeset,
+                                        char **mask);
+
+/*
+ * Setters
+ */
+int virDomainNumatuneSet(virDomainDefPtr def, int placement,
+                         int mode, virBitmapPtr nodeset)
+    ATTRIBUTE_NONNULL(1);
+
+/*
+ * Other accessors
+ */
+bool virDomainNumatuneEquals(virDomainNumatunePtr n1,
+                             virDomainNumatunePtr n2);
+
+bool virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune);
 
 #endif /* __NUMATUNE_CONF_H__ */
index cf8bb916953365ee6e698db2bfab57ba1703de58..0494d9dfae23eb49d4b4007a48b420700822b962 100644 (file)
@@ -200,6 +200,7 @@ virDomainDefGetDefaultEmulator;
 virDomainDefGetSecurityLabelDef;
 virDomainDefMaybeAddController;
 virDomainDefMaybeAddInput;
+virDomainDefNeedsPlacementAdvice;
 virDomainDefNew;
 virDomainDefParseFile;
 virDomainDefParseNode;
@@ -607,10 +608,20 @@ virNodeDeviceObjUnlock;
 
 
 # conf/numatune_conf.h
+virDomainNumatuneEquals;
+virDomainNumatuneFormatNodeset;
+virDomainNumatuneFormatXML;
+virDomainNumatuneFree;
+virDomainNumatuneGetMode;
+virDomainNumatuneGetNodeset;
+virDomainNumatuneHasPlacementAuto;
+virDomainNumatuneMaybeFormatNodeset;
 virDomainNumatuneMemModeTypeFromString;
 virDomainNumatuneMemModeTypeToString;
+virDomainNumatuneParseXML;
 virDomainNumatunePlacementTypeFromString;
 virDomainNumatunePlacementTypeToString;
+virDomainNumatuneSet;
 
 
 # conf/nwfilter_conf.h
index b584e33b2d1c0eb69841ee4c012849476717f220..cc938239cfabdb692929ceb644489903231a0ba4 100644 (file)
@@ -79,22 +79,11 @@ static int virLXCCgroupSetupCpusetTune(virDomainDefPtr def,
             goto cleanup;
     }
 
-    if ((def->numatune.memory.nodemask ||
-         (def->numatune.memory.placement_mode ==
-          VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)) &&
-          def->numatune.memory.mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
-        if (def->numatune.memory.placement_mode ==
-            VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)
-            mask = virBitmapFormat(nodemask);
-        else
-            mask = virBitmapFormat(def->numatune.memory.nodemask);
-
-        if (!mask)
-            return -1;
+    if (virDomainNumatuneMaybeFormatNodeset(def->numatune, nodemask, &mask) < 0)
+        goto cleanup;
 
-        if (virCgroupSetCpusetMems(cgroup, mask) < 0)
-            goto cleanup;
-    }
+    if (mask && virCgroupSetCpusetMems(cgroup, mask) < 0)
+        goto cleanup;
 
     ret = 0;
  cleanup:
index 03b1d311d74d216d6b431232cbc374f0ec258565..fd93f479f9b340a59ff9e2ad1e84333e4261d6fe 100644 (file)
@@ -653,10 +653,7 @@ static int virLXCControllerGetNumadAdvice(virLXCControllerPtr ctrl,
     /* Get the advisory nodeset from numad if 'placement' of
      * either <vcpu> or <numatune> is 'auto'.
      */
-    if ((ctrl->def->placement_mode ==
-         VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) ||
-        (ctrl->def->numatune.memory.placement_mode ==
-         VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)) {
+    if (virDomainDefNeedsPlacementAdvice(ctrl->def)) {
         nodeset = virNumaGetAutoPlacementAdvice(ctrl->def->vcpus,
                                                 ctrl->def->mem.cur_balloon);
         if (!nodeset)
index 30f7e55405d5509bce3f5fbe2e1f72465af263e9..bb15a36ca63b0da521513608ca8fbd4f130f80d7 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * lxc_native.c: LXC native configuration import
  *
+ * Copyright (c) 2014 Red Hat, Inc.
  * Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
  *
  * This library is free software; you can redistribute it and/or
@@ -708,6 +709,7 @@ static int
 lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties)
 {
     virConfValuePtr value;
+    virBitmapPtr nodeset = NULL;
 
     if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.cpus")) &&
             value->str) {
@@ -719,12 +721,15 @@ lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties)
     }
 
     if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.mems")) &&
-            value->str) {
-        def->numatune.memory.placement_mode = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
-        def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
-        if (virBitmapParse(value->str, 0, &def->numatune.memory.nodemask,
-                           VIR_DOMAIN_CPUMASK_LEN) < 0)
+        value->str) {
+        if (virBitmapParse(value->str, 0, &nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0)
             return -1;
+        if (virDomainNumatuneSet(def, VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC,
+                                 VIR_DOMAIN_NUMATUNE_MEM_STRICT, nodeset) < 0) {
+            virBitmapFree(nodeset);
+            return -1;
+        }
+        virBitmapFree(nodeset);
     }
 
     return 0;
index 43568d1e0abaac96c319a8abd40afab08de08316..a503dea932b27a9b77bf712dfacb52bfb34e590c 100644 (file)
@@ -2078,12 +2078,7 @@ parallelsApplyChanges(virDomainObjPtr dom, virDomainDefPtr new)
         return -1;
     }
 
-    if (old->numatune.memory.mode != new->numatune.memory.mode ||
-        old->numatune.memory.placement_mode != new->numatune.memory.placement_mode ||
-        ((old->numatune.memory.nodemask != NULL || new->numatune.memory.nodemask != NULL) &&
-         (old->numatune.memory.nodemask == NULL || new->numatune.memory.nodemask == NULL ||
-        !virBitmapEqual(old->numatune.memory.nodemask, new->numatune.memory.nodemask)))){
-
+    if (!virDomainNumatuneEquals(old->numatune, new->numatune)) {
         virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                         _("numa parameters are not supported "
                           "by parallels driver"));
index a24975b17d0829a5b2534b1bbda320a29e70deb3..dd393eea89632c626878c2413d1da8dfdb4e77cf 100644 (file)
@@ -601,23 +601,14 @@ qemuSetupCpusetCgroup(virDomainObjPtr vm,
     if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET))
         return 0;
 
-    if ((vm->def->numatune.memory.nodemask ||
-         (vm->def->numatune.memory.placement_mode ==
-          VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)) &&
-        vm->def->numatune.memory.mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
-
-        if (vm->def->numatune.memory.placement_mode ==
-            VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)
-            mem_mask = virBitmapFormat(nodemask);
-        else
-            mem_mask = virBitmapFormat(vm->def->numatune.memory.nodemask);
-
-        if (!mem_mask)
-            goto cleanup;
+    if (virDomainNumatuneMaybeFormatNodeset(vm->def->numatune,
+                                            nodemask,
+                                            &mem_mask) < 0)
+        goto cleanup;
 
-        if (virCgroupSetCpusetMems(priv->cgroup, mem_mask) < 0)
-            goto cleanup;
-    }
+    if (mem_mask &&
+        virCgroupSetCpusetMems(priv->cgroup, mem_mask) < 0)
+        goto cleanup;
 
     if (vm->def->cpumask ||
         (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)) {
index 85c368419fb556589af7fb758edabc0ba47fb811..e166ca431b76bae7ddd7fda0c8ef3df2dc944693 100644 (file)
@@ -8637,7 +8637,8 @@ qemuDomainSetNumaParamsLive(virDomainObjPtr vm,
     size_t i = 0;
     int ret = -1;
 
-    if (vm->def->numatune.memory.mode != VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
+    if (virDomainNumatuneGetMode(vm->def->numatune) !=
+        VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("change of nodeset for running domain "
                          "requires strict numa mode"));
@@ -8712,6 +8713,8 @@ qemuDomainSetNumaParameters(virDomainPtr dom,
     virQEMUDriverConfigPtr cfg = NULL;
     virCapsPtr caps = NULL;
     qemuDomainObjPrivatePtr priv;
+    virBitmapPtr nodeset = NULL;
+    int mode = -1;
 
     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                   VIR_DOMAIN_AFFECT_CONFIG, -1);
@@ -8752,65 +8755,47 @@ qemuDomainSetNumaParameters(virDomainPtr dom,
         virTypedParameterPtr param = &params[i];
 
         if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) {
-            int mode = param->value.i;
+            mode = param->value.i;
 
-            if (mode >= VIR_DOMAIN_NUMATUNE_PLACEMENT_LAST ||
-                mode < VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT)
-            {
+            if (mode < 0 || mode >= VIR_DOMAIN_NUMATUNE_MEM_LAST) {
                 virReportError(VIR_ERR_INVALID_ARG,
-                               _("unsupported numa_mode: '%d'"), mode);
+                               _("unsupported numatune mode: '%d'"), mode);
                 goto cleanup;
             }
 
-            if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-                vm->def->numatune.memory.mode != mode) {
-                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                               _("can't change numa mode for running domain"));
-                goto cleanup;
-            }
-
-            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
-                persistentDef->numatune.memory.mode = mode;
-
         } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
-            virBitmapPtr nodeset = NULL;
-
             if (virBitmapParse(param->value.s, 0, &nodeset,
-                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
+                               VIR_DOMAIN_CPUMASK_LEN) < 0)
                 goto cleanup;
-            }
 
-            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
-                if (qemuDomainSetNumaParamsLive(vm, caps, nodeset) < 0) {
-                    virBitmapFree(nodeset);
-                    goto cleanup;
-                }
-
-                /* update vm->def here so that dumpxml can read the new
-                 * values from vm->def. */
-                virBitmapFree(vm->def->numatune.memory.nodemask);
-
-                vm->def->numatune.memory.placement_mode =
-                    VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
-                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
+            if (virBitmapIsAllClear(nodeset)) {
+                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                               _("Invalid nodeset for numatune"));
+                goto cleanup;
             }
+        }
+    }
 
-            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
-                virBitmapFree(persistentDef->numatune.memory.nodemask);
-
-                persistentDef->numatune.memory.nodemask = nodeset;
-                persistentDef->numatune.memory.placement_mode =
-                    VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
-                nodeset = NULL;
-            }
-            virBitmapFree(nodeset);
+    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+        if (mode != -1 &&
+            virDomainNumatuneGetMode(vm->def->numatune) != mode) {
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("can't change numatune mode for running domain"));
+            goto cleanup;
         }
+
+        if (nodeset &&
+            qemuDomainSetNumaParamsLive(vm, caps, nodeset) < 0)
+            goto cleanup;
+
+        if (virDomainNumatuneSet(vm->def, -1, mode, nodeset) < 0)
+            goto cleanup;
     }
 
     if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
-        if (!persistentDef->numatune.memory.placement_mode)
-            persistentDef->numatune.memory.placement_mode =
-                VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO;
+        if (virDomainNumatuneSet(persistentDef, -1, mode, nodeset) < 0)
+            goto cleanup;
+
         if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
             goto cleanup;
     }
@@ -8818,6 +8803,7 @@ qemuDomainSetNumaParameters(virDomainPtr dom,
     ret = 0;
 
  cleanup:
+    virBitmapFree(nodeset);
     if (vm)
         virObjectUnlock(vm);
     virObjectUnref(caps);
@@ -8886,15 +8872,17 @@ qemuDomainGetNumaParameters(virDomainPtr dom,
             if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                         VIR_TYPED_PARAM_INT, 0) < 0)
                 goto cleanup;
+
             if (flags & VIR_DOMAIN_AFFECT_CONFIG)
-                param->value.i = persistentDef->numatune.memory.mode;
+                param->value.i = virDomainNumatuneGetMode(persistentDef->numatune);
             else
-                param->value.i = vm->def->numatune.memory.mode;
+                param->value.i = virDomainNumatuneGetMode(vm->def->numatune);
             break;
 
         case 1: /* fill numa nodeset here */
             if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
-                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
+                nodeset = virDomainNumatuneFormatNodeset(persistentDef->numatune,
+                                                         NULL);
                 if (!nodeset)
                     goto cleanup;
             } else {
index d8bb67999033b225948e11da31d3d10fe43e3b09..4c57f15a20c8a083f2b1f50825ebe89b8122e4ea 100644 (file)
@@ -3898,10 +3898,7 @@ int qemuProcessStart(virConnectPtr conn,
     /* Get the advisory nodeset from numad if 'placement' of
      * either <vcpu> or <numatune> is 'auto'.
      */
-    if ((vm->def->placement_mode ==
-         VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) ||
-        (vm->def->numatune.memory.placement_mode ==
-         VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)) {
+    if (virDomainDefNeedsPlacementAdvice(vm->def)) {
         nodeset = virNumaGetAutoPlacementAdvice(vm->def->vcpus,
                                                 vm->def->mem.max_balloon);
         if (!nodeset)
@@ -3909,8 +3906,7 @@ int qemuProcessStart(virConnectPtr conn,
 
         VIR_DEBUG("Nodeset returned from numad: %s", nodeset);
 
-        if (virBitmapParse(nodeset, 0, &nodemask,
-                           VIR_DOMAIN_CPUMASK_LEN) < 0)
+        if (virBitmapParse(nodeset, 0, &nodemask, VIR_DOMAIN_CPUMASK_LEN) < 0)
             goto cleanup;
     }
     hookData.nodemask = nodemask;
index bc5180a2eb4d83a1c80704f3fa4840214e4fb578..087f6798d1c6081dbcd59b960f3cc654c87d9855 100644 (file)
@@ -87,11 +87,10 @@ virNumaGetAutoPlacementAdvice(unsigned short vcpus ATTRIBUTE_UNUSED,
 
 #if WITH_NUMACTL
 int
-virNumaSetupMemoryPolicy(virDomainNumatune numatune,
+virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune,
                          virBitmapPtr nodemask)
 {
     nodemask_t mask;
-    int mode = -1;
     int node = -1;
     int ret = -1;
     int bit = 0;
@@ -99,19 +98,9 @@ virNumaSetupMemoryPolicy(virDomainNumatune numatune,
     int maxnode = 0;
     virBitmapPtr tmp_nodemask = NULL;
 
-    if (numatune.memory.placement_mode ==
-        VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC) {
-        if (!numatune.memory.nodemask)
-            return 0;
-        VIR_DEBUG("Set NUMA memory policy with specified nodeset");
-        tmp_nodemask = numatune.memory.nodemask;
-    } else if (numatune.memory.placement_mode ==
-               VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO) {
-        VIR_DEBUG("Set NUMA memory policy with advisory nodeset from numad");
-        tmp_nodemask = nodemask;
-    } else {
+    tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask);
+    if (!tmp_nodemask)
         return 0;
-    }
 
     if (numa_available() < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -134,13 +123,15 @@ virNumaSetupMemoryPolicy(virDomainNumatune numatune,
         nodemask_set(&mask, bit);
     }
 
-    mode = numatune.memory.mode;
-
-    if (mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
+    switch (virDomainNumatuneGetMode(numatune)) {
+    case VIR_DOMAIN_NUMATUNE_MEM_STRICT:
         numa_set_bind_policy(1);
         numa_set_membind(&mask);
         numa_set_bind_policy(0);
-    } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_PREFERRED) {
+        break;
+
+    case VIR_DOMAIN_NUMATUNE_MEM_PREFERRED:
+    {
         int nnodes = 0;
         for (i = 0; i < NUMA_NUM_NODES; i++) {
             if (nodemask_isset(&mask, i)) {
@@ -158,17 +149,16 @@ virNumaSetupMemoryPolicy(virDomainNumatune numatune,
 
         numa_set_bind_policy(0);
         numa_set_preferred(node);
-    } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) {
-        numa_set_interleave_mask(&mask);
-    } else {
-        /* XXX: Shouldn't go here, as we already do checking when
-         * parsing domain XML.
-         */
-        virReportError(VIR_ERR_XML_ERROR,
-                       "%s", _("Invalid mode for memory NUMA tuning."));
-        goto cleanup;
     }
+    break;
 
+    case VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE:
+        numa_set_interleave_mask(&mask);
+        break;
+
+    case VIR_DOMAIN_NUMATUNE_MEM_LAST:
+        break;
+    }
     ret = 0;
 
  cleanup:
@@ -327,10 +317,10 @@ virNumaGetNodeCPUs(int node,
 
 #else
 int
-virNumaSetupMemoryPolicy(virDomainNumatune numatune,
+virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune,
                          virBitmapPtr nodemask ATTRIBUTE_UNUSED)
 {
-    if (numatune.memory.nodemask) {
+    if (virDomainNumatuneGetNodeset(numatune, NULL)) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("libvirt is compiled without NUMA tuning support"));
 
index d2ab6af0aa6cd4b031f3d439e53848345ae121bd..13ebec6273a46dfe657a7fc8faf7423775de29d1 100644 (file)
@@ -31,7 +31,7 @@
 char *virNumaGetAutoPlacementAdvice(unsigned short vcups,
                                     unsigned long long balloon);
 
-int virNumaSetupMemoryPolicy(virDomainNumatune numatune,
+int virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune,
                              virBitmapPtr nodemask);
 
 bool virNumaIsAvailable(void);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-auto-prefer.xml
new file mode 100644 (file)
index 0000000..63f0d1f
--- /dev/null
@@ -0,0 +1,29 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='auto'>1</vcpu>
+  <numatune>
+    <memory mode='preferred'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='65536'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-numatune-auto-prefer.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-numatune-auto-prefer.xml
new file mode 100644 (file)
index 0000000..19761b4
--- /dev/null
@@ -0,0 +1,29 @@
+<domain type='qemu'>
+  <name>QEMUGuest</name>
+  <uuid>9f4b6512-e73a-4a25-93e8-5307802821ce</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>65536</currentMemory>
+  <vcpu placement='auto'>1</vcpu>
+  <numatune>
+    <memory mode='preferred' placement='auto'/>
+  </numatune>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu>
+    <numa>
+      <cell id='0' cpus='0' memory='65536'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/kvm</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
index 172ce2bc3d59d4857ffdddb94bec88ff1420f03b..8b1b11ad26e7af91ba43e4586c84e88048f4b30a 100644 (file)
@@ -373,6 +373,8 @@ mymain(void)
     DO_TEST_DIFFERENT("cpu-numa1");
     DO_TEST_DIFFERENT("cpu-numa2");
 
+    DO_TEST_DIFFERENT("numatune-auto-prefer");
+
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);