On Wed, 2014-10-29 at 14:20 +0100, Martin Kletzander wrote: > On Wed, Oct 29, 2014 at 08:33:32PM +0800, Chen Fan wrote: > >For memnode in numatune element, the range of attribute 'nodeset' > >was not validated. on my host maxnodes was 1, but when setting nodeset > >to '0-2' or more, guest also started succuss. there probably was qemu's > >bug too. > > > > How about rewording this as: > > There was no check for 'nodeset' attribute in numatune-related > elements. This patch adds validation that any nodeset specified does > not exceed maximum host node. Look good to me. > > >Signed-off-by: Chen Fan <chen.fan.fnst@xxxxxxxxxxxxxx> > >--- > > src/conf/numatune_conf.c | 28 +++++++++++++ > > src/conf/numatune_conf.h | 1 + > > src/libvirt_private.syms | 2 + > > src/qemu/qemu_command.c | 3 ++ > > src/qemu/qemu_command.h | 1 + > > src/util/virbitmap.c | 49 ++++++++++++++++++++++ > > src/util/virbitmap.h | 3 ++ > > src/util/virnuma.c | 33 +++++++++++++++ > > src/util/virnuma.h | 2 + > > ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 ++++++++++++++++ > > tests/qemuxml2argvmock.c | 9 ++++ > > tests/qemuxml2argvtest.c | 1 + > > tests/virbitmaptest.c | 26 +++++++++++- > > 13 files changed, 192 insertions(+), 1 deletion(-) > > create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml > > > >diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c > >index 21d9a64..54f309a 100644 > >--- a/src/conf/numatune_conf.c > >+++ b/src/conf/numatune_conf.c > >@@ -612,3 +612,31 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune) > > > > return false; > > } > >+ > >+int > >+virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune) > >+{ > >+ int ret = -1; > >+ virBitmapPtr nodemask = NULL; > >+ size_t i; > >+ > >+ if (!numatune) > >+ return ret; > >+ > >+ nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); > >+ if (nodemask) { > >+ ret = virBitmapLastSetBit(nodemask, -1); > >+ } > >+ for (i = 0; i < numatune->nmem_nodes; i++) { > > Well, you're using the advantage of accessible structure members here > (numatune->nmem_nodes), but using accessors around. These particular > ones are useless here when you don't need any of the logic they > provide. right, I should use numatune->mem_nodes[i].nodeset directly. > > >+ int bit = -1; > >+ nodemask = virDomainNumatuneGetNodeset(numatune, NULL, i); > >+ if (!nodemask) > >+ continue; > >+ > >+ bit = virBitmapLastSetBit(nodemask, -1); > >+ if (bit > ret) > >+ ret = bit; > >+ } > >+ > >+ return ret; > >+} > >diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h > >index 5254629..15dc0d6 100644 > >--- a/src/conf/numatune_conf.h > >+++ b/src/conf/numatune_conf.h > >@@ -102,4 +102,5 @@ bool virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); > > > > bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); > > > >+int virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune); > > #endif /* __NUMATUNE_CONF_H__ */ > >diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > >index d63a8f0..4a30ad7 100644 > >--- a/src/libvirt_private.syms > >+++ b/src/libvirt_private.syms > >@@ -1011,6 +1011,7 @@ virBitmapFree; > > virBitmapGetBit; > > virBitmapIsAllClear; > > virBitmapIsAllSet; > >+virBitmapLastSetBit; > > virBitmapNew; > > virBitmapNewCopy; > > virBitmapNewData; > >@@ -1728,6 +1729,7 @@ virNumaGetPageInfo; > > virNumaGetPages; > > virNumaIsAvailable; > > virNumaNodeIsAvailable; > >+virNumaNodesetIsAvailable; > > virNumaSetPagePoolSize; > > virNumaSetupMemoryPolicy; > > > >diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > >index 2e5af4f..9757d3e 100644 > >--- a/src/qemu/qemu_command.c > >+++ b/src/qemu/qemu_command.c > >@@ -6663,6 +6663,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, > > goto cleanup; > > } > > > >+ if (!virNumaNodesetIsAvailable(def->numatune)) > >+ goto cleanup; > >+ > > for (i = 0; i < def->mem.nhugepages; i++) { > > ssize_t next_bit, pos = 0; > > > >diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h > >index aa40c9e..f263665 100644 > >--- a/src/qemu/qemu_command.h > >+++ b/src/qemu/qemu_command.h > >@@ -27,6 +27,7 @@ > > # include "domain_addr.h" > > # include "domain_conf.h" > > # include "vircommand.h" > >+# include "virnuma.h" > > # include "capabilities.h" > > # include "qemu_conf.h" > > # include "qemu_domain.h" > >diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c > >index b6bd074..aed525a 100644 > >--- a/src/util/virbitmap.c > >+++ b/src/util/virbitmap.c > >@@ -651,6 +651,55 @@ virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) > > } > > > > /** > >+ * virBitmapLastSetBit: > >+ * @bitmap: the bitmap > >+ * @pos: the position after which to search for a set bit > >+ * > >+ * Search for the last set bit before position @pos in bitmap @bitmap. > >+ * @pos can be -1 to search for the last set bit. Position starts > >+ * at max_bit. > >+ * > >+ * Returns the position of the found bit, or -1 if no bit found. > >+ */ > >+ssize_t > >+virBitmapLastSetBit(virBitmapPtr bitmap, ssize_t pos) > >+{ > >+ size_t nl; > >+ size_t nb; > >+ unsigned long bits; > >+ size_t i; > >+ > >+ if (pos < 0) > >+ pos = bitmap->max_bit; > >+ > >+ pos--; > >+ > >+ if (pos >= bitmap->max_bit) > >+ return -1; > >+ > >+ nl = pos / VIR_BITMAP_BITS_PER_UNIT; > >+ nb = pos % VIR_BITMAP_BITS_PER_UNIT; > >+ > > You can use VIR_BITMAP_UNIT_OFFSET and VIR_BITMAP_BIT_OFFSET macros here. > > >+ bits = bitmap->map[nl] & ((1UL << (nb + 1)) - 1); > >+ > > VIR_BITMAP_BIT(nb + 1) - 1 > > >+ while (bits == 0 && --nl < bitmap->map_len) { > >+ bits = bitmap->map[nl]; > >+ } > >+ > > Reading this is weird, especially when you're using underflowing of > size_t, eww. I think you made this unnecessarily complicated by > keeping "pos" attribute there. If (and only if) you really need to > have @pos there, I rather suggest making this a wrapper using > virBitmapNextSetBit(), but I hope you don't. I will delete the "pos" attribute. > > >+ if (bits == 0) > >+ return -1; > >+ > >+ i = VIR_BITMAP_BITS_PER_UNIT - 1; > >+ for (; i < VIR_BITMAP_BITS_PER_UNIT; i--) { > >+ if (bits & 1UL << i) { > >+ return i + nl * VIR_BITMAP_BITS_PER_UNIT; > >+ } > >+ } > >+ > >+ return -1; > >+} > >+ > >+/** > > * virBitmapNextClearBit: > > * @bitmap: the bitmap > > * @pos: the position after which to search for a clear bit > >diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h > >index 4493cc9..c0fad55 100644 > >--- a/src/util/virbitmap.h > >+++ b/src/util/virbitmap.h > >@@ -105,6 +105,9 @@ bool virBitmapIsAllClear(virBitmapPtr bitmap) > > ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) > > ATTRIBUTE_NONNULL(1); > > > >+ssize_t virBitmapLastSetBit(virBitmapPtr bitmap, ssize_t pos) > >+ ATTRIBUTE_NONNULL(1); > >+ > > ssize_t virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) > > ATTRIBUTE_NONNULL(1); > > > > Could you separate these virbitmap.* hunks and the tests for them into > their own patch, please? Sure. > > >diff --git a/src/util/virnuma.c b/src/util/virnuma.c > >index 690615f..fbe8fd1 100644 > >--- a/src/util/virnuma.c > >+++ b/src/util/virnuma.c > >@@ -312,6 +312,33 @@ virNumaGetNodeCPUs(int node, > > > > return ret; > > } > >+ > >+bool > >+virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) > >+{ > >+ int maxnode; > >+ int bit; > >+ > >+ if (!numatune) > >+ return true; > >+ > >+ if ((maxnode = virNumaGetMaxNode()) < 0) > >+ return false; > >+ > >+ maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; > >+ > >+ bit = virDomainNumatuneSpecifiedMaxNode(numatune); > >+ if (bit > maxnode) > >+ goto error; > >+ > >+ return true; > >+ > >+ error: > >+ virReportError(VIR_ERR_INTERNAL_ERROR, > >+ _("NUMA node %d is out of range"), bit); > >+ return false; > >+} > >+ > > # undef MASK_CPU_ISSET > > # undef n_bits > > > >@@ -373,6 +400,12 @@ virNumaGetNodeCPUs(int node ATTRIBUTE_UNUSED, > > _("NUMA isn't available on this host")); > > return -1; > > } > >+ > >+bool > >+virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) > >+{ > >+ return true; > >+} > > #endif > > > > In what case would you like this to return true? when libvirt does not support numa, we can not check it. maybe we should return false if setting nodeset. Thanks, Chen > > > > >diff --git a/src/util/virnuma.h b/src/util/virnuma.h > >index 04b6b8c..e129bb2 100644 > >--- a/src/util/virnuma.h > >+++ b/src/util/virnuma.h > >@@ -34,6 +34,8 @@ char *virNumaGetAutoPlacementAdvice(unsigned short vcups, > > int virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, > > virBitmapPtr nodemask); > > > >+bool virNumaNodesetIsAvailable(virDomainNumatunePtr numatune); > >+ > > bool virNumaIsAvailable(void); > > int virNumaGetMaxNode(void); > > bool virNumaNodeIsAvailable(int node); > >diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml b/tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml > >new file mode 100644 > >index 0000000..84a560a > >--- /dev/null > >+++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml > >@@ -0,0 +1,35 @@ > >+<domain type='qemu'> > >+ <name>QEMUGuest1</name> > >+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> > >+ <memory unit='KiB'>1048576</memory> > >+ <currentMemory unit='KiB'>1048576</currentMemory> > >+ <vcpu placement='static'>4</vcpu> > >+ <numatune> > >+ <memnode cellid='0' mode='strict' nodeset='0-8'/> > >+ <memnode cellid='1' mode='strict' nodeset='0'/> > >+ </numatune> > >+ <os> > >+ <type arch='i686' machine='pc'>hvm</type> > >+ <boot dev='hd'/> > >+ </os> > >+ <cpu> > >+ <numa> > >+ <cell id='0' cpus='0-1' memory='524288'/> > >+ <cell id='1' cpus='2-3' memory='524288'/> > >+ </numa> > >+ </cpu> > >+ <clock offset='utc'/> > >+ <on_poweroff>destroy</on_poweroff> > >+ <on_reboot>restart</on_reboot> > >+ <on_crash>destroy</on_crash> > >+ <devices> > >+ <emulator>/usr/bin/qemu-system-x86_64</emulator> > >+ <disk type='block' device='disk'> > >+ <source dev='/dev/HostVG/QEMUGuest1'/> > >+ <target dev='hda' bus='ide'/> > >+ <address type='drive' controller='0' bus='0' target='0' unit='0'/> > >+ </disk> > >+ <controller type='ide' index='0'/> > >+ <memballoon model='virtio'/> > >+ </devices> > >+</domain> > >diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c > >index bff3b0f..316bf0b 100644 > >--- a/tests/qemuxml2argvmock.c > >+++ b/tests/qemuxml2argvmock.c > >@@ -21,6 +21,7 @@ > > #include <config.h> > > > > #include "internal.h" > >+#include "virnuma.h" > > #include <time.h> > > > > time_t time(time_t *t) > >@@ -30,3 +31,11 @@ time_t time(time_t *t) > > *t = ret; > > return ret; > > } > >+ > >+int > >+virNumaGetMaxNode(void) > >+{ > >+ const int maxnodes = 7; > >+ > >+ return maxnodes; > >+} > >diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c > >index 0e9fab9..bab6d0d 100644 > >--- a/tests/qemuxml2argvtest.c > >+++ b/tests/qemuxml2argvtest.c > >@@ -1250,6 +1250,7 @@ mymain(void) > > DO_TEST_FAILURE("numatune-memnode-no-memory", NONE); > > > > DO_TEST("numatune-auto-nodeset-invalid", NONE); > >+ DO_TEST_FAILURE("numatune-static-nodeset-exceed-hostnode", QEMU_CAPS_OBJECT_MEMORY_RAM); > > DO_TEST_PARSE_ERROR("numatune-memnode-nocpu", NONE); > > DO_TEST_PARSE_ERROR("numatune-memnodes-problematic", NONE); > > DO_TEST("numad", NONE); > >diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c > >index ea832ad..21e8611 100644 > >--- a/tests/virbitmaptest.c > >+++ b/tests/virbitmaptest.c > >@@ -171,7 +171,7 @@ test3(const void *data ATTRIBUTE_UNUSED) > > return ret; > > } > > > >-/* test for virBitmapNextSetBit, virBitmapNextClearBit */ > >+/* test for virBitmapNextSetBit, virBitmapLastSetBit, virBitmapNextClearBit */ > > static int > > test4(const void *data ATTRIBUTE_UNUSED) > > { > >@@ -200,6 +200,9 @@ test4(const void *data ATTRIBUTE_UNUSED) > > if (virBitmapNextSetBit(bitmap, -1) != -1) > > goto error; > > > >+ if (virBitmapLastSetBit(bitmap, -1) != -1) > >+ goto error; > >+ > > for (i = 0; i < size; i++) { > > if (virBitmapNextClearBit(bitmap, i - 1) != i) > > goto error; > >@@ -232,6 +235,18 @@ test4(const void *data ATTRIBUTE_UNUSED) > > if (virBitmapNextSetBit(bitmap, i) != -1) > > goto error; > > > >+ j = sizeof(bitsPos)/sizeof(int) - 1; > >+ i = -1; > >+ > >+ while (j < ARRAY_CARDINALITY(bitsPos)) { > >+ i = virBitmapLastSetBit(bitmap, i); > >+ if (i != bitsPos[j--]) > >+ goto error; > >+ } > >+ > >+ if (virBitmapLastSetBit(bitmap, i) != -1) > >+ goto error; > >+ > > j = 0; > > i = -1; > > > >@@ -255,6 +270,15 @@ test4(const void *data ATTRIBUTE_UNUSED) > > if (virBitmapNextSetBit(bitmap, i) != -1) > > goto error; > > > >+ for (i = size; i > 0; i--) { > >+ if (virBitmapLastSetBit(bitmap, i) != i - 1) > >+ goto error; > >+ } > >+ > >+ if (virBitmapLastSetBit(bitmap, i) != -1) > >+ goto error; > >+ > >+ > > if (virBitmapNextClearBit(bitmap, -1) != -1) > > goto error; > > > >-- > >1.9.3 > > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list