[libvirt] [PATCH v1 1/8] New functions for virBitmap

In many places we store bitmap info in a chunk of data (pointed to by a char *), and have redundant codes to set/unset bits. This patch extends virBitmap, and convert those codes to use virBitmap in subsquent patches. --- .gitignore | 1 + src/libvirt_private.syms | 10 ++ src/util/bitmap.c | 391 +++++++++++++++++++++++++++++++++++++++++++++- src/util/bitmap.h | 23 +++ tests/Makefile.am | 8 +- tests/virbitmaptest.c | 134 ++++++++++++++++ 6 files changed, 562 insertions(+), 5 deletions(-) create mode 100644 tests/virbitmaptest.c diff --git a/.gitignore b/.gitignore index 5041ddf..9aaa1f5 100644 --- a/.gitignore +++ b/.gitignore @@ -155,6 +155,7 @@ /tests/storagebackendsheepdogtest /tests/utiltest /tests/viratomictest +/tests/virbitmaptest /tests/virauthconfigtest /tests/virbuftest /tests/virdrivermoduletest diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 27eb43e..9c27218 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -7,11 +7,21 @@ # bitmap.h virBitmapAlloc; +virBitmapAllocFromData; +virBitmapClearAll; virBitmapClearBit; +virBitmapCmp; +virBitmapCopy; +virBitmapFormat; virBitmapFree; virBitmapGetBit; +virBitmapIsAllSet; +virBitmapParse; +virBitmapSetAll; virBitmapSetBit; +virBitmapSize; virBitmapString; +virBitmapToData; # buf.h diff --git a/src/util/bitmap.c b/src/util/bitmap.c index 53a8a38..2e668c6 100644 --- a/src/util/bitmap.c +++ b/src/util/bitmap.c @@ -33,15 +33,17 @@ #include "bitmap.h" #include "memory.h" #include "buf.h" +#include "util.h" +#include "c-ctype.h" struct _virBitmap { size_t size; - unsigned long *map; + unsigned char *map; }; -#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned long) * CHAR_BIT) +#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned char) * CHAR_BIT) #define VIR_BITMAP_UNIT_OFFSET(b) ((b) / VIR_BITMAP_BITS_PER_UNIT) #define VIR_BITMAP_BIT_OFFSET(b) ((b) % VIR_BITMAP_BITS_PER_UNIT) #define VIR_BITMAP_BIT(b) (1UL << VIR_BITMAP_BIT_OFFSET(b)) @@ -129,6 +131,12 @@ int virBitmapClearBit(virBitmapPtr bitmap, size_t b) return 0; } +/* Helper function. caller must ensure b < bitmap->size */ +static bool bitmapIsset(virBitmapPtr bitmap, size_t b) +{ + return !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b)); +} + /** * virBitmapGetBit: * @bitmap: Pointer to bitmap @@ -145,7 +153,7 @@ int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) if (bitmap->size <= b) return -1; - *result = !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b)); + *result = bitmapIsset(bitmap, b); return 0; } @@ -168,7 +176,7 @@ char *virBitmapString(virBitmapPtr bitmap) VIR_BITMAP_BITS_PER_UNIT; while (sz--) { - virBufferAsprintf(&buf, "%0*lx", + virBufferAsprintf(&buf, "%0*hx", VIR_BITMAP_BITS_PER_UNIT / 4, bitmap->map[sz]); } @@ -180,3 +188,378 @@ char *virBitmapString(virBitmapPtr bitmap) return virBufferContentAndReset(&buf); } + +/** + * virBitmapFormat: + * @bitmap: the bitmap + * + * This function is the counterpart of virBitmapParse. This function creates + * a human-readable string representing the bits in bitmap. + * + * See virBitmapParse for the format of @str. + * + * Returns the string on success or NULL otherwise. Caller should call + * VIR_FREE to free the string. + */ +char *virBitmapFormat(virBitmapPtr bitmap) +{ + virBuffer buf =VIR_BUFFER_INITIALIZER; + int first = -1; + int start, cur; + int ret; + bool isset; + + if (!bitmap) + return NULL; + + cur = 0; + start = -1; + while (cur < bitmap->size) { + ret = virBitmapGetBit(bitmap, cur, &isset); + if (ret != 0) + goto error; + else if (isset) { + if (start == -1) + start = cur; + } else if (start != -1) { + if (!first) + virBufferAddLit(&buf, ","); + else + first = 0; + if (cur == start + 1) + virBufferAsprintf(&buf, "%d", start); + else + virBufferAsprintf(&buf, "%d-%d", start, cur - 1); + start = -1; + } + cur++; + } + + if (start != -1) { + if (!first) + virBufferAddLit(&buf, ","); + if (cur == start + 1) + virBufferAsprintf(&buf, "%d", start); + else + virBufferAsprintf(&buf, "%d-%d", start, cur - 1); + } + + if (virBufferError(&buf)) { +error: + virBufferFreeAndReset(&buf); + return NULL; + } + + return virBufferContentAndReset(&buf); +} + +/** + * virBitmapParse: + * @str: points to a string representing a human-readable bitmap + * @bitmap: a bitmap created from @str + * @bitmapSize: the upper limit of num of bits in created bitmap + * + * This function is the counterpart of virBitmapFormat. This function creates + * a bitmap, in which bits are set according to the content of @str. + * + * @str is a comma separated string of fields N, which means a number of bit + * to set, and ^N, which means to unset the bit, and N-M for ranges of bits + * to set. + * + * Returns the number of bits set in @bitmap, or -1 in case of error. + */ + +int virBitmapParse(const char *str, + char sep, + virBitmapPtr *bitmap, + size_t bitmapSize) +{ + int ret = 0; + int neg = 0; + const char *cur; + char *tmp; + int i, start, last; + + if (!str) + return -1; + + cur = str; + virSkipSpaces(&cur); + + if (*cur == 0) + return -1; + + *bitmap = virBitmapAlloc(bitmapSize); + if (!*bitmap) + return -1; + + while (*cur != 0 && *cur != sep) { + /* + * 3 constructs are allowed: + * - N : a single CPU number + * - N-M : a range of CPU numbers with N < M + * - ^N : remove a single CPU number from the current set + */ + if (*cur == '^') { + cur++; + neg = 1; + } + + if (!c_isdigit(*cur)) + goto parse_error; + + if (virStrToLong_i(cur, &tmp, 10, &start) < 0) + goto parse_error; + if (start < 0) + goto parse_error; + + cur = tmp; + + virSkipSpaces(&cur); + + if (*cur == ',' || *cur == 0 || *cur == sep) { + if (neg) { + if (bitmapIsset(*bitmap, start)) { + ignore_value(virBitmapClearBit(*bitmap, start)); + ret--; + } + } else { + if (!bitmapIsset(*bitmap, start)) { + ignore_value(virBitmapSetBit(*bitmap, start)); + ret++; + } + } + } else if (*cur == '-') { + if (neg) + goto parse_error; + + cur++; + virSkipSpaces(&cur); + + if (virStrToLong_i(cur, &tmp, 10, &last) < 0) + goto parse_error; + if (last < start) + goto parse_error; + + cur = tmp; + + for (i = start; i <= last; i++) { + if (!bitmapIsset(*bitmap, i)) { + ignore_value(virBitmapSetBit(*bitmap, i)); + ret++; + } + } + + virSkipSpaces(&cur); + } + + if (*cur == ',') { + cur++; + virSkipSpaces(&cur); + neg = 0; + } else if(*cur == 0 || *cur == sep) { + break; + } else { + goto parse_error; + } + } + + return ret; + +parse_error: + virBitmapFree(*bitmap); + *bitmap = NULL; + return -1; +} + +/** + * virBitmapCopy: + * @src: the source bitmap. + * + * Makes a copy of bitmap @src. + * + * returns the copied bitmap on success, or NULL otherwise. Caller + * should call virBitmapFree to free the returned bitmap. + */ +virBitmapPtr virBitmapCopy(virBitmapPtr src) +{ + virBitmapPtr dst; + size_t sz; + + sz = (src->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + if (VIR_ALLOC(dst) < 0) + return NULL; + + if (VIR_ALLOC_N(dst->map, sz) < 0) { + VIR_FREE(dst); + return NULL; + } + + memcpy(dst->map, src->map, sz); + dst->size = src->size; + + return dst; +} + +/** + * virBitmapAllocFromData: + * @data: the data + * @len: len of @data in byte + * + * Allocate a bitmap from a chunk of data containing bits + * information + * + * Returns a pointer to the allocated bitmap or NULL if + * memory cannot be allocated. + */ +virBitmapPtr virBitmapAllocFromData(void *data, int len) +{ + virBitmapPtr bitmap; + + bitmap = virBitmapAlloc(len * CHAR_BIT); + if (!bitmap) + return NULL; + + memcpy(bitmap->map, data, len); + + return bitmap; +} + +/** + * virBitmapToData: + * @data: the data + * @len: len of @data in byte + * + * Convert a bitmap to a chunk of data containing bits information. + * Data consists of sequential bytes, with lower bytes containing + * lower bits. + * + * Returns 0 on success, -1 otherwise. + */ +int virBitmapToData(virBitmapPtr bitmap, char **data, int *dataLen) +{ + size_t sz; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + if (VIR_ALLOC_N(*data, sz) < 0) + return -1; + + memcpy(*data, bitmap->map, sz); + *dataLen = sz; + + return 0; +} + +/** + * virBitmapCmp: + * @b1: bitmap 1 + * @b2: bitmap 2 + * + * Compares two bitmaps. Returns true if two bitmaps have exactly + * the same set of bits set, otherwise false. + */ +bool virBitmapCmp(virBitmapPtr b1, virBitmapPtr b2) +{ + virBitmapPtr b; + size_t sz1, sz2, sz; + int i; + + sz1 = (b1->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + sz2 = (b2->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + sz = sz1 < sz2 ? sz1 : sz2; + + for (i = 0; i < sz; i++) { + if (b1->map[i] != b2->map[i]) + return false; + } + + b = sz1 > sz ? b1 : b2; + sz = sz1 > sz ? sz1 : sz2; + for (; i < sz; i++) { + if (b->map[i]) + return false; + } + + return true; +} + +size_t virBitmapSize(virBitmapPtr bitmap) +{ + return bitmap->size; +} + +/** + * virBitmapSetAll: + * @bitmap: the bitmap + * + * set all bits in @bitmap. + */ +void virBitmapSetAll(virBitmapPtr bitmap) +{ + int i; + size_t sz; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + for (i = 0; i < sz; i++) + bitmap->map[i] = -1; +} + +/** + * virBitmapClearAll: + * @bitmap: the bitmap + * + * clear all bits in @bitmap. + */ +void virBitmapClearAll(virBitmapPtr bitmap) +{ + int i; + size_t sz; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + for (i = 0; i < sz; i++) + bitmap->map[i] = 0; +} + +/** + * virBitmapIsAllSet: + * @bitmap: the bitmap to check + * + * check if all bits in @bitmap are set. + */ +bool virBitmapIsAllSet(virBitmapPtr bitmap) +{ + int i; + int unusedBits; + size_t sz, tmp; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + unusedBits = sz * VIR_BITMAP_BITS_PER_UNIT - bitmap->size; + + tmp = sz; + if (unusedBits > 0) + tmp = sz - 1; + + for (i = 0; i < tmp; i++) + if (bitmap->map[i] != (unsigned char)-1) + return false; + + if (unusedBits > 0) { + if ((bitmap->map[sz - 1] & ((1 << (VIR_BITMAP_BITS_PER_UNIT - unusedBits + 1)) - 1)) + != ((1 << (VIR_BITMAP_BITS_PER_UNIT - unusedBits + 1)) - 1)) + return false; + } + + return true; +} diff --git a/src/util/bitmap.h b/src/util/bitmap.h index c3e6222..4823604 100644 --- a/src/util/bitmap.h +++ b/src/util/bitmap.h @@ -62,4 +62,27 @@ int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) char *virBitmapString(virBitmapPtr bitmap) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; +char *virBitmapFormat(virBitmapPtr bitmap); + +int virBitmapParse(const char *str, + char sep, + virBitmapPtr *bitmap, + size_t bitmapSize); + +virBitmapPtr virBitmapCopy(virBitmapPtr src); + +virBitmapPtr virBitmapAllocFromData(void *data, int len); + +int virBitmapToData(virBitmapPtr bitmap, char **data, int *dataLen); + +bool virBitmapCmp(virBitmapPtr b1, virBitmapPtr b2); + +size_t virBitmapSize(virBitmapPtr bitmap); + +void virBitmapSetAll(virBitmapPtr bitmap); + +void virBitmapClearAll(virBitmapPtr bitmap); + +bool virBitmapIsAllSet(virBitmapPtr bitmap); + #endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 8cf8015..ec436df 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -92,7 +92,8 @@ test_programs = virshtest sockettest \ viratomictest \ utiltest virnettlscontexttest shunloadtest \ virtimetest viruritest virkeyfiletest \ - virauthconfigtest + virauthconfigtest \ + virbitmaptest if WITH_SECDRIVER_SELINUX test_programs += securityselinuxtest @@ -562,6 +563,10 @@ viratomictest_SOURCES = \ viratomictest.c testutils.h testutils.c viratomictest_LDADD = $(LDADDS) +virbitmaptest_SOURCES = \ + virbitmaptest.c testutils.h testutils.c +virbitmaptest_LDADD = $(LDADDS) + jsontest_SOURCES = \ jsontest.c testutils.h testutils.c jsontest_LDADD = $(LDADDS) @@ -592,6 +597,7 @@ shunloadtest_SOURCES = \ shunloadtest_LDADD = $(LIB_PTHREAD) shunloadtest_DEPENDENCIES = libshunload.la + if WITH_CIL CILOPTFLAGS = CILOPTINCS = diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c new file mode 100644 index 0000000..c688618 --- /dev/null +++ b/tests/virbitmaptest.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2012 Fujitsu. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <time.h> +#include <sched.h> + +#include "testutils.h" + +#include "bitmap.h" + +static int test1(const void *data ATTRIBUTE_UNUSED) +{ + virBitmapPtr bitmap; + int size; + int bit; + bool result; + + size = 1024; + bit = 100; + bitmap = virBitmapAlloc(size); + if (virBitmapSetBit(bitmap, bit) < 0) + return -1; + + if (virBitmapGetBit(bitmap, bit, &result) < 0) + return -1; + + if (!result) + return -1; + + if (virBitmapGetBit(bitmap, bit + 1, &result) < 0) + return -1; + + if (result) + return -1; + + return 0; +} + +bool testBit(virBitmapPtr bitmap, unsigned int start, unsigned int end) +{ + int i; + bool result; + + for (i = start; i <= end; i++) { + if (virBitmapGetBit(bitmap, i, &result) < 0) + return 0; + if (!result) + return 0; + } + + return 1; +} + +static int test2(const void *data ATTRIBUTE_UNUSED) +{ + const char *bitsString1 = "1-32,50,88-99,1021-1023"; + char *bitsString2 = NULL; + virBitmapPtr bitmap = NULL; + int ret = -1; + int size = 1024; + + if (virBitmapParse(bitsString1, 0, &bitmap, size) < 0) + goto error; + + if (!testBit(bitmap, 1, 32)) + goto error; + if (!testBit(bitmap, 50, 50)) + goto error; + if (!testBit(bitmap, 88, 99)) + goto error; + if (!testBit(bitmap, 1021, 1023)) + goto error; + + if (testBit(bitmap, 0, 0)) + goto error; + if (testBit(bitmap, 33,49)) + goto error; + if (testBit(bitmap, 51,87)) + goto error; + if (testBit(bitmap, 100,1020)) + goto error; + + bitsString2 = virBitmapFormat(bitmap); + if (strcmp(bitsString1, bitsString2)) + goto error; + + virBitmapSetAll(bitmap); + if (!testBit(bitmap, 0, size - 1)) + goto error; + + virBitmapClearAll(bitmap); + if (testBit(bitmap, 0, size - 1)) + goto error; + + ret = 0; + +error: + virBitmapFree(bitmap); + VIR_FREE(bitsString2); + return ret; +} + +static int +mymain(void) +{ + int ret = 0; + + if (virtTestRun("test1", 1, test1, NULL) < 0) + ret = -1; + if (virtTestRun("test2", 1, test2, NULL) < 0) + ret = -1; + + return ret; +} + +VIRT_TEST_MAIN(mymain) -- 1.7.10.2

--- src/conf/domain_conf.c | 98 +++++++++++------------------------------------ src/conf/domain_conf.h | 3 +- src/qemu/qemu_cgroup.c | 3 +- src/qemu/qemu_driver.c | 14 +++++-- src/qemu/qemu_process.c | 20 ++++++---- 5 files changed, 49 insertions(+), 89 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 224aec5..2f496fa 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -52,6 +52,7 @@ #include "netdev_bandwidth_conf.h" #include "netdev_vlan_conf.h" #include "device_conf.h" +#include "bitmap.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN @@ -1505,17 +1506,16 @@ virDomainVcpuPinDefCopy(virDomainVcpuPinDefPtr *src, int nvcpupin) for (i = 0; i < nvcpupin; i++) { if (VIR_ALLOC(ret[i]) < 0) goto no_memory; - if (VIR_ALLOC_N(ret[i]->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) - goto no_memory; ret[i]->vcpuid = src[i]->vcpuid; - memcpy(ret[i]->cpumask, src[i]->cpumask, VIR_DOMAIN_CPUMASK_LEN); + if ((ret[i]->cpumask = virBitmapCopy(src[i]->cpumask)) == NULL) + goto no_memory; } return ret; no_memory: while (i >= 0) { - VIR_FREE(ret[i]->cpumask); + virBitmapFree(ret[i]->cpumask); VIR_FREE(ret[i]); } VIR_FREE(ret); @@ -7947,12 +7947,8 @@ virDomainVcpuPinDefParseXML(const xmlNodePtr node, char *set = tmp; int cpumasklen = VIR_DOMAIN_CPUMASK_LEN; - if (VIR_ALLOC_N(def->cpumask, cpumasklen) < 0) { - virReportOOMError(); - goto error; - } - if (virDomainCpuSetParse(set, 0, def->cpumask, - cpumasklen) < 0) + if (virBitmapParse(set, 0, &def->cpumask, + cpumasklen) < 0) goto error; VIR_FREE(tmp); } else { @@ -11005,34 +11001,6 @@ virDomainVcpuPinFindByVcpu(virDomainVcpuPinDefPtr *def, return NULL; } -static char *bitmapFromBytemap(unsigned char *bytemap, int maplen) -{ - char *bitmap = NULL; - int i; - - if (VIR_ALLOC_N(bitmap, VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - goto cleanup; - } - - /* Reset bitmap to all 0s. */ - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) - bitmap[i] = 0; - - /* Convert bitmap (bytemap) to bitmap, which is byte map? */ - for (i = 0; i < maplen; i++) { - int cur; - - for (cur = 0; cur < 8; cur++) { - if (bytemap[i] & (1 << cur)) - bitmap[i * 8 + cur] = 1; - } - } - -cleanup: - return bitmap; -} - int virDomainVcpuPinAdd(virDomainVcpuPinDefPtr *vcpupin_list, int *nvcpupin, unsigned char *cpumap, @@ -11040,20 +11008,19 @@ int virDomainVcpuPinAdd(virDomainVcpuPinDefPtr *vcpupin_list, int vcpu) { virDomainVcpuPinDefPtr vcpupin = NULL; - char *cpumask = NULL; if (!vcpupin_list) return -1; - if ((cpumask = bitmapFromBytemap(cpumap, maplen)) == NULL) - return -1; - vcpupin = virDomainVcpuPinFindByVcpu(vcpupin_list, *nvcpupin, vcpu); if (vcpupin) { vcpupin->vcpuid = vcpu; - vcpupin->cpumask = cpumask; + virBitmapFree(vcpupin->cpumask); + vcpupin->cpumask = virBitmapAllocFromData(cpumap, maplen); + if (!vcpupin->cpumask) + return -1; return 0; } @@ -11062,16 +11029,15 @@ int virDomainVcpuPinAdd(virDomainVcpuPinDefPtr *vcpupin_list, if (VIR_ALLOC(vcpupin) < 0) { virReportOOMError(); - VIR_FREE(cpumask); return -1; } vcpupin->vcpuid = vcpu; - vcpupin->cpumask = cpumask; - + vcpupin->cpumask = virBitmapAllocFromData(cpumap, maplen); + if (!vcpupin->cpumask) + return -1; if (VIR_REALLOC_N(vcpupin_list, *nvcpupin + 1) < 0) { virReportOOMError(); - VIR_FREE(cpumask); VIR_FREE(vcpupin); return -1; } @@ -11126,47 +11092,31 @@ virDomainEmulatorPinAdd(virDomainDefPtr def, int maplen) { virDomainVcpuPinDefPtr emulatorpin = NULL; - char *cpumask = NULL; - int i; - - if (VIR_ALLOC_N(cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - goto cleanup; - } - - /* Convert bitmap (cpumap) to cpumask, which is byte map. */ - for (i = 0; i < maplen; i++) { - int cur; - - for (cur = 0; cur < 8; cur++) { - if (cpumap[i] & (1 << cur)) - cpumask[i * 8 + cur] = 1; - } - } if (!def->cputune.emulatorpin) { /* No emulatorpin exists yet. */ if (VIR_ALLOC(emulatorpin) < 0) { virReportOOMError(); - goto cleanup; + return -1; } emulatorpin->vcpuid = -1; - emulatorpin->cpumask = cpumask; + emulatorpin->cpumask = virBitmapAllocFromData(cpumap, maplen); + if (!emulatorpin->cpumask) + return -1; + def->cputune.emulatorpin = emulatorpin; } else { /* Since there is only 1 emulatorpin for each vm, * juest replace the old one. */ VIR_FREE(def->cputune.emulatorpin->cpumask); - def->cputune.emulatorpin->cpumask = cpumask; + def->cputune.emulatorpin->cpumask = virBitmapAllocFromData(cpumap, maplen); + if (!def->cputune.emulatorpin->cpumask) + return -1; } return 0; - -cleanup: - VIR_FREE(cpumask); - return -1; } int @@ -13133,8 +13083,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, def->cputune.vcpupin[i]->vcpuid); char *cpumask = NULL; - cpumask = virDomainCpuSetFormat(def->cputune.vcpupin[i]->cpumask, - VIR_DOMAIN_CPUMASK_LEN); + cpumask = virBitmapFormat(def->cputune.vcpupin[i]->cpumask); if (cpumask == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -13151,8 +13100,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAsprintf(buf, " <emulatorpin "); char *cpumask = NULL; - cpumask = virDomainCpuSetFormat(def->cputune.emulatorpin->cpumask, - VIR_DOMAIN_CPUMASK_LEN); + cpumask = virBitmapFormat(def->cputune.emulatorpin->cpumask); if (cpumask == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to format cpuset for emulator")); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 9ee57e1..ba05fde 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -46,6 +46,7 @@ # include "virnetdevvlan.h" # include "virobject.h" # include "device_conf.h" +# include "bitmap.h" /* forward declarations of all device types, required by * virDomainDeviceDef @@ -1524,7 +1525,7 @@ typedef struct _virDomainVcpuPinDef virDomainVcpuPinDef; typedef virDomainVcpuPinDef *virDomainVcpuPinDefPtr; struct _virDomainVcpuPinDef { int vcpuid; - char *cpumask; + virBitmapPtr cpumask; }; void virDomainVcpuPinDefFree(virDomainVcpuPinDefPtr *def, int nvcpupin); diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index df67ff3..f093b75 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -513,8 +513,7 @@ int qemuSetupCgroupEmulatorPin(virCgroupPtr cgroup, int rc = 0; char *new_cpus = NULL; - new_cpus = virDomainCpuSetFormat(vcpupin->cpumask, - VIR_DOMAIN_CPUMASK_LEN); + new_cpus = virBitmapFormat(vcpupin->cpumask); if (!new_cpus) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to convert cpu mask")); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9a25253..ae7cc02 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3953,8 +3953,9 @@ qemudDomainGetVcpuPinInfo(virDomainPtr dom, int maxcpu, hostcpus, vcpu, pcpu; int n; virDomainVcpuPinDefPtr *vcpupin_list; - char *cpumask = NULL; + virBitmapPtr cpumask = NULL; unsigned char *cpumap; + bool pinned; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); @@ -4013,7 +4014,9 @@ qemudDomainGetVcpuPinInfo(virDomainPtr dom, cpumask = vcpupin_list[n]->cpumask; cpumap = VIR_GET_CPUMAP(cpumaps, maplen, vcpu); for (pcpu = 0; pcpu < maxcpu; pcpu++) { - if (cpumask[pcpu] == 0) + if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0) + goto cleanup; + if (!pinned) VIR_UNUSE_CPU(cpumap, pcpu); } } @@ -4203,7 +4206,8 @@ qemudDomainGetEmulatorPinInfo(virDomainPtr dom, int ret = -1; int maxcpu, hostcpus, pcpu; virDomainVcpuPinDefPtr emulatorpin = NULL; - char *cpumask = NULL; + virBitmapPtr cpumask = NULL; + bool pinned; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); @@ -4252,7 +4256,9 @@ qemudDomainGetEmulatorPinInfo(virDomainPtr dom, cpumask = emulatorpin->cpumask; for (pcpu = 0; pcpu < maxcpu; pcpu++) { - if (cpumask[pcpu] == 0) + if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0) + goto cleanup; + if (!pinned) VIR_UNUSE_CPU(cpumaps, pcpu); } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7f85aea..e153d98 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1945,10 +1945,11 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn, virDomainDefPtr def = vm->def; virNodeInfo nodeinfo; pid_t vcpupid; - unsigned char *cpumask; + virBitmapPtr cpumask; int vcpu, cpumaplen, hostcpus, maxcpu, n; unsigned char *cpumap = NULL; int ret = -1; + bool result; if (virNodeGetInfo(conn, &nodeinfo) != 0) { return -1; @@ -1980,11 +1981,13 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn, vcpu = def->cputune.vcpupin[n]->vcpuid; memset(cpumap, 0, cpumaplen); - cpumask = (unsigned char *)def->cputune.vcpupin[n]->cpumask; + cpumask = def->cputune.vcpupin[n]->cpumask; vcpupid = priv->vcpupids[vcpu]; - for (i = 0 ; i < VIR_DOMAIN_CPUMASK_LEN ; i++) { - if (cpumask[i]) + for (i = 0 ; i < virBitmapSize(cpumask); i++) { + if (virBitmapGetBit(cpumask, i, &result) < 0) + goto cleanup; + if (result) VIR_USE_CPU(cpumap, i); } @@ -2009,11 +2012,12 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn, { virDomainDefPtr def = vm->def; pid_t pid = vm->pid; - unsigned char *cpumask = NULL; + virBitmapPtr cpumask = NULL; unsigned char *cpumap = NULL; virNodeInfo nodeinfo; int cpumaplen, hostcpus, maxcpu, i; int ret = -1; + bool result; if (virNodeGetInfo(conn, &nodeinfo) != 0) return -1; @@ -2033,9 +2037,11 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn, return -1; } - cpumask = (unsigned char *)def->cputune.emulatorpin->cpumask; + cpumask = def->cputune.emulatorpin->cpumask; for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (cpumask[i]) + if (virBitmapGetBit(cpumask, i, &result) < 0) + goto cleanup; + if (result) VIR_USE_CPU(cpumap, i); } -- 1.7.10.2

On 08/30/2012 02:55 AM, Hu Tao wrote:
--- src/conf/domain_conf.c | 98 +++++++++++------------------------------------ src/conf/domain_conf.h | 3 +- src/qemu/qemu_cgroup.c | 3 +- src/qemu/qemu_driver.c | 14 +++++-- src/qemu/qemu_process.c | 20 ++++++---- 5 files changed, 49 insertions(+), 89 deletions(-)
@@ -11005,34 +11001,6 @@ virDomainVcpuPinFindByVcpu(virDomainVcpuPinDefPtr *def, return NULL; }
-static char *bitmapFromBytemap(unsigned char *bytemap, int maplen) -{ - char *bitmap = NULL; - int i; - - if (VIR_ALLOC_N(bitmap, VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - goto cleanup; - } - - /* Reset bitmap to all 0s. */ - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) - bitmap[i] = 0; - - /* Convert bitmap (bytemap) to bitmap, which is byte map? */
Thank you for killing this horrible comment!
- for (i = 0; i < maplen; i++) { - int cur; - - for (cur = 0; cur < 8; cur++) { - if (bytemap[i] & (1 << cur)) - bitmap[i * 8 + cur] = 1; - } - }
Indeed, the old code was converting a packed array (8 bits per char) to an exploded array (1 bit per char), but using horribly confusing names in the process. But the new code uses virBitmap from the get-go.
@@ -11040,20 +11008,19 @@ int virDomainVcpuPinAdd(virDomainVcpuPinDefPtr *vcpupin_list, int vcpu) { virDomainVcpuPinDefPtr vcpupin = NULL; - char *cpumask = NULL;
if (!vcpupin_list) return -1;
- if ((cpumask = bitmapFromBytemap(cpumap, maplen)) == NULL) - return -1; - vcpupin = virDomainVcpuPinFindByVcpu(vcpupin_list, *nvcpupin, vcpu); if (vcpupin) { vcpupin->vcpuid = vcpu; - vcpupin->cpumask = cpumask; + virBitmapFree(vcpupin->cpumask); + vcpupin->cpumask = virBitmapAllocFromData(cpumap, maplen); + if (!vcpupin->cpumask) + return -1;
Shouldn't this report OOM?
return 0; } @@ -11062,16 +11029,15 @@ int virDomainVcpuPinAdd(virDomainVcpuPinDefPtr *vcpupin_list,
if (VIR_ALLOC(vcpupin) < 0) { virReportOOMError(); - VIR_FREE(cpumask); return -1; } vcpupin->vcpuid = vcpu; - vcpupin->cpumask = cpumask; - + vcpupin->cpumask = virBitmapAllocFromData(cpumap, maplen); + if (!vcpupin->cpumask) + return -1;
And this?
@@ -1980,11 +1981,13 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn, vcpu = def->cputune.vcpupin[n]->vcpuid;
memset(cpumap, 0, cpumaplen); - cpumask = (unsigned char *)def->cputune.vcpupin[n]->cpumask; + cpumask = def->cputune.vcpupin[n]->cpumask; vcpupid = priv->vcpupids[vcpu];
- for (i = 0 ; i < VIR_DOMAIN_CPUMASK_LEN ; i++) { - if (cpumask[i]) + for (i = 0 ; i < virBitmapSize(cpumask); i++) { + if (virBitmapGetBit(cpumask, i, &result) < 0) + goto cleanup; + if (result) VIR_USE_CPU(cpumap, i);
I wonder if virBitmap _also_ needs new functions for converting between virBitmapPtr and the API maps, instead of having to handroll our own VIR_[UN]USE_CPU loops. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

--- src/lxc/lxc_controller.c | 19 +++++------- src/qemu/qemu_driver.c | 54 ++++++++++++++++++++------------- src/qemu/qemu_process.c | 75 ++++++++++++---------------------------------- src/util/processinfo.c | 36 ++++++++++++---------- src/util/processinfo.h | 9 ++---- 5 files changed, 83 insertions(+), 110 deletions(-) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..d6298b0 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -493,8 +493,7 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) { int i, hostcpus, maxcpu = CPU_SETSIZE; virNodeInfo nodeinfo; - unsigned char *cpumap; - int cpumaplen; + virBitmapPtr cpumap; VIR_DEBUG("Setting CPU affinity"); @@ -507,37 +506,33 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) if (maxcpu > hostcpus) maxcpu = hostcpus; - cpumaplen = VIR_CPU_MAPLEN(maxcpu); - if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) { - virReportOOMError(); + cpumap = virBitmapAlloc(maxcpu); + if (!cpumap) return -1; - } if (ctrl->def->cpumask) { /* XXX why don't we keep 'cpumask' in the libvirt cpumap * format to start with ?!?! */ for (i = 0 ; i < maxcpu && i < ctrl->def->cpumasklen ; i++) if (ctrl->def->cpumask[i]) - VIR_USE_CPU(cpumap, i); + ignore_value(virBitmapSetBit(cpumap, i)); } else { /* You may think this is redundant, but we can't assume libvirtd * itself is running on all pCPUs, so we need to explicitly set * the spawned LXC instance to all pCPUs if no map is given in * its config file */ - for (i = 0 ; i < maxcpu ; i++) - VIR_USE_CPU(cpumap, i); + virBitmapSetAll(cpumap); } /* We are pressuming we are running between fork/exec of LXC * so use '0' to indicate our own process ID. No threads are * running at this point */ - if (virProcessInfoSetAffinity(0, /* Self */ - cpumap, cpumaplen, maxcpu) < 0) { + if (virProcessInfoSetAffinity(0 /* Self */, cpumap) < 0) { VIR_FREE(cpumap); return -1; } - VIR_FREE(cpumap); + virBitmapFree(cpumap); return 0; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ae7cc02..cb7b156 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -92,6 +92,7 @@ #include "virnodesuspend.h" #include "virtime.h" #include "virtypedparam.h" +#include "bitmap.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -3762,10 +3763,10 @@ qemudDomainPinVcpuFlags(virDomainPtr dom, virNodeInfo nodeinfo; int ret = -1; qemuDomainObjPrivatePtr priv; - bool canResetting = true; + bool canResetting = false; int newVcpuPinNum = 0; virDomainVcpuPinDefPtr *newVcpuPin = NULL; - int pcpu; + virBitmapPtr pcpumap = NULL; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); @@ -3801,15 +3802,16 @@ qemudDomainPinVcpuFlags(virDomainPtr dom, maxcpu = maplen * 8; if (maxcpu > hostcpus) maxcpu = hostcpus; + + pcpumap = virBitmapAllocFromData(cpumap, maplen); + if (!pcpumap) + goto cleanup; + /* pinning to all physical cpus means resetting, * so check if we can reset setting. */ - for (pcpu = 0; pcpu < hostcpus; pcpu++) { - if ((cpumap[pcpu/8] & (1 << (pcpu % 8))) == 0) { - canResetting = false; - break; - } - } + if (virBitmapIsAllSet(pcpumap)) + canResetting = true; if (flags & VIR_DOMAIN_AFFECT_LIVE) { @@ -3852,8 +3854,7 @@ qemudDomainPinVcpuFlags(virDomainPtr dom, goto cleanup; } } else { - if (virProcessInfoSetAffinity(priv->vcpupids[vcpu], - cpumap, maplen, maxcpu) < 0) { + if (virProcessInfoSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to set cpu affinity for vcpu %d"), vcpu); @@ -3926,6 +3927,7 @@ cleanup: virCgroupFree(&cgroup_dom); if (vm) virDomainObjUnlock(vm); + virBitmapFree(pcpumap); return ret; } @@ -4044,10 +4046,10 @@ qemudDomainPinEmulator(virDomainPtr dom, virNodeInfo nodeinfo; int ret = -1; qemuDomainObjPrivatePtr priv; - bool canResetting = true; - int pcpu; + bool canResetting = false; int newVcpuPinNum = 0; virDomainVcpuPinDefPtr *newVcpuPin = NULL; + virBitmapPtr pcpumap = NULL; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); @@ -4076,15 +4078,16 @@ qemudDomainPinEmulator(virDomainPtr dom, maxcpu = maplen * 8; if (maxcpu > hostcpus) maxcpu = hostcpus; + + pcpumap = virBitmapAllocFromData(cpumap, maplen); + if (!pcpumap) + goto cleanup; + /* pinning to all physical cpus means resetting, * so check if we can reset setting. */ - for (pcpu = 0; pcpu < hostcpus; pcpu++) { - if ((cpumap[pcpu/8] & (1 << (pcpu % 8))) == 0) { - canResetting = false; - break; - } - } + if (virBitmapIsAllSet(pcpumap)) + canResetting = true; pid = vm->pid; @@ -4122,7 +4125,7 @@ qemudDomainPinEmulator(virDomainPtr dom, } } } else { - if (virProcessInfoSetAffinity(pid, cpumap, maplen, maxcpu) < 0) { + if (virProcessInfoSetAffinity(pid, pcpumap) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, "%s", _("failed to set cpu affinity for " "emulator threads")); @@ -4187,6 +4190,7 @@ cleanup: virCgroupFree(&cgroup_emulator); if (cgroup_dom) virCgroupFree(&cgroup_dom); + virBitmapFree(pcpumap); if (vm) virDomainObjUnlock(vm); @@ -4341,10 +4345,20 @@ qemudDomainGetVcpus(virDomainPtr dom, if (priv->vcpupids != NULL) { for (v = 0 ; v < maxinfo ; v++) { unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v); + virBitmapPtr map = NULL; + char *tmpmap = NULL; + int tmpmapLen = 0; if (virProcessInfoGetAffinity(priv->vcpupids[v], - cpumap, maplen, maxcpu) < 0) + &map, maxcpu) < 0) goto cleanup; + virBitmapToData(map, &tmpmap, &tmpmapLen); + if (tmpmapLen > maplen) + tmpmapLen = maplen; + memcpy(cpumap, tmpmap, tmpmapLen); + + VIR_FREE(tmpmap); + virBitmapFree(map); } } else { virReportError(VIR_ERR_OPERATION_INVALID, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index e153d98..d4baaa5 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1839,8 +1839,7 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, int ret = -1; int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN; virNodeInfo nodeinfo; - unsigned char *cpumap; - int cpumaplen; + virBitmapPtr cpumap; VIR_DEBUG("Setting CPU affinity"); @@ -1853,8 +1852,8 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, if (maxcpu > hostcpus) maxcpu = hostcpus; - cpumaplen = VIR_CPU_MAPLEN(maxcpu); - if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) { + cpumap = virBitmapAlloc(maxcpu); + if (!cpumap) { virReportOOMError(); return -1; } @@ -1867,7 +1866,8 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, int cur_ncpus = driver->caps->host.numaCell[i]->ncpus; if (nodemask[i]) { for (j = 0; j < cur_ncpus; j++) - VIR_USE_CPU(cpumap, driver->caps->host.numaCell[i]->cpus[j]); + ignore_value(virBitmapSetBit(cpumap, + driver->caps->host.numaCell[i]->cpus[j])); } } } else { @@ -1877,14 +1877,13 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, * format to start with ?!?! */ for (i = 0 ; i < maxcpu && i < vm->def->cpumasklen ; i++) if (vm->def->cpumask[i]) - VIR_USE_CPU(cpumap, i); + ignore_value(virBitmapSetBit(cpumap, i)); } else { /* You may think this is redundant, but we can't assume libvirtd * itself is running on all pCPUs, so we need to explicitly set * the spawned QEMU instance to all pCPUs if no map is given in * its config file */ - for (i = 0 ; i < maxcpu ; i++) - VIR_USE_CPU(cpumap, i); + virBitmapSetAll(cpumap); } } @@ -1892,14 +1891,13 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, * so use '0' to indicate our own process ID. No threads are * running at this point */ - if (virProcessInfoSetAffinity(0, /* Self */ - cpumap, cpumaplen, maxcpu) < 0) + if (virProcessInfoSetAffinity(0 /* Self */, cpumap) < 0) goto cleanup; ret = 0; cleanup: - VIR_FREE(cpumap); + virBitmapFree(cpumap); return ret; } @@ -1946,10 +1944,8 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn, virNodeInfo nodeinfo; pid_t vcpupid; virBitmapPtr cpumask; - int vcpu, cpumaplen, hostcpus, maxcpu, n; - unsigned char *cpumap = NULL; + int vcpu, hostcpus, maxcpu, n; int ret = -1; - bool result; if (virNodeGetInfo(conn, &nodeinfo) != 0) { return -1; @@ -1965,43 +1961,26 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn, } hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo); - cpumaplen = VIR_CPU_MAPLEN(hostcpus); - maxcpu = cpumaplen * 8; + maxcpu = VIR_CPU_MAPLEN(hostcpus) * CHAR_BIT; if (maxcpu > hostcpus) maxcpu = hostcpus; - if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) { - virReportOOMError(); - return -1; - } - for (n = 0; n < def->cputune.nvcpupin; n++) { - int i; vcpu = def->cputune.vcpupin[n]->vcpuid; - memset(cpumap, 0, cpumaplen); - cpumask = def->cputune.vcpupin[n]->cpumask; + cpumask = virBitmapCopy(def->cputune.vcpupin[n]->cpumask); vcpupid = priv->vcpupids[vcpu]; - for (i = 0 ; i < virBitmapSize(cpumask); i++) { - if (virBitmapGetBit(cpumask, i, &result) < 0) - goto cleanup; - if (result) - VIR_USE_CPU(cpumap, i); - } - + /* TODO: constrain cpumask from maxcpu */ if (virProcessInfoSetAffinity(vcpupid, - cpumap, - cpumaplen, - maxcpu) < 0) { + cpumask) < 0) { goto cleanup; } } ret = 0; cleanup: - VIR_FREE(cpumap); return ret; } @@ -2013,11 +1992,9 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn, virDomainDefPtr def = vm->def; pid_t pid = vm->pid; virBitmapPtr cpumask = NULL; - unsigned char *cpumap = NULL; virNodeInfo nodeinfo; - int cpumaplen, hostcpus, maxcpu, i; + int hostcpus, maxcpu; int ret = -1; - bool result; if (virNodeGetInfo(conn, &nodeinfo) != 0) return -1; @@ -2026,35 +2003,21 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn, return 0; hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo); - cpumaplen = VIR_CPU_MAPLEN(hostcpus); - maxcpu = cpumaplen * CHAR_BIT; + maxcpu = VIR_CPU_MAPLEN(hostcpus) * CHAR_BIT; if (maxcpu > hostcpus) maxcpu = hostcpus; - if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) { - virReportOOMError(); - return -1; - } - - cpumask = def->cputune.emulatorpin->cpumask; - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (virBitmapGetBit(cpumask, i, &result) < 0) - goto cleanup; - if (result) - VIR_USE_CPU(cpumap, i); - } + cpumask = virBitmapCopy(def->cputune.emulatorpin->cpumask); + /* TODO: constrain cpumask from maxcpu */ if (virProcessInfoSetAffinity(pid, - cpumap, - cpumaplen, - maxcpu) < 0) { + cpumask) < 0) { goto cleanup; } ret = 0; cleanup: - VIR_FREE(cpumap); return ret; } diff --git a/src/util/processinfo.c b/src/util/processinfo.c index 16ab8af..b7d2ed0 100644 --- a/src/util/processinfo.c +++ b/src/util/processinfo.c @@ -30,12 +30,10 @@ #if HAVE_SCHED_GETAFFINITY -int virProcessInfoSetAffinity(pid_t pid, - const unsigned char *map, - size_t maplen, - int maxcpu) +int virProcessInfoSetAffinity(pid_t pid, virBitmapPtr map) { int i; + bool set = false; # ifdef CPU_ALLOC /* New method dynamically allocates cpu mask, allowing unlimted cpus */ int numcpus = 1024; @@ -59,8 +57,10 @@ realloc: } CPU_ZERO_S(masklen, mask); - for (i = 0 ; i < maxcpu ; i++) { - if (VIR_CPU_USABLE(map, maplen, 0, i)) + for (i = 0 ; i < virBitmapSize(map); i++) { + if (virBitmapGetBit(map, i, &set) < 0) + return -1; + if (set) CPU_SET_S(i, masklen, mask); } @@ -81,8 +81,10 @@ realloc: cpu_set_t mask; CPU_ZERO(&mask); - for (i = 0 ; i < maxcpu ; i++) { - if (VIR_CPU_USABLE(map, maplen, 0, i)) + for (i = 0 ; i < virBitmapSize(map); i++) { + if (virBitmapGetBit(map, i, &set) < 0) + return -1; + if (set) CPU_SET(i, &mask); } @@ -97,8 +99,7 @@ realloc: } int virProcessInfoGetAffinity(pid_t pid, - unsigned char *map, - size_t maplen ATTRIBUTE_UNUSED, + virBitmapPtr *map, int maxcpu) { int i; @@ -137,9 +138,15 @@ realloc: return -1; } + *map = virBitmapAlloc(maxcpu); + if (!map) { + virReportOOMError(); + return -1; + } + for (i = 0 ; i < maxcpu ; i++) if (CPU_ISSET_S(i, masklen, mask)) - VIR_USE_CPU(map, i); + ignore_value(virBitmapSetBit(*map, i)); CPU_FREE(mask); # else /* Legacy method uses a fixed size cpu mask, only allows upto 1024 cpus */ @@ -163,9 +170,7 @@ realloc: #else /* HAVE_SCHED_GETAFFINITY */ int virProcessInfoSetAffinity(pid_t pid ATTRIBUTE_UNUSED, - const unsigned char *map ATTRIBUTE_UNUSED, - size_t maplen ATTRIBUTE_UNUSED, - int maxcpu ATTRIBUTE_UNUSED) + virBitmapPtr map ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", _("Process CPU affinity is not supported on this platform")); @@ -173,8 +178,7 @@ int virProcessInfoSetAffinity(pid_t pid ATTRIBUTE_UNUSED, } int virProcessInfoGetAffinity(pid_t pid ATTRIBUTE_UNUSED, - unsigned char *map ATTRIBUTE_UNUSED, - size_t maplen ATTRIBUTE_UNUSED, + virBitmapPtr *map ATTRIBUTE_UNUSED, int maxcpu ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", diff --git a/src/util/processinfo.h b/src/util/processinfo.h index a648bb8..0424643 100644 --- a/src/util/processinfo.h +++ b/src/util/processinfo.h @@ -23,15 +23,12 @@ # define __VIR_PROCESSINFO_H__ # include "internal.h" +# include "bitmap.h" -int virProcessInfoSetAffinity(pid_t pid, - const unsigned char *map, - size_t maplen, - int maxcpu); +int virProcessInfoSetAffinity(pid_t pid, virBitmapPtr map); int virProcessInfoGetAffinity(pid_t pid, - unsigned char *map, - size_t maplen, + virBitmapPtr *map, int maxcpu); #endif /* __VIR_PROCESSINFO_H__ */ -- 1.7.10.2

On 08/30/2012 02:55 AM, Hu Tao wrote:
if (ctrl->def->cpumask) { /* XXX why don't we keep 'cpumask' in the libvirt cpumap * format to start with ?!?! */
This comment now feels a bit out of date.
for (i = 0 ; i < maxcpu && i < ctrl->def->cpumasklen ; i++) if (ctrl->def->cpumask[i]) - VIR_USE_CPU(cpumap, i); + ignore_value(virBitmapSetBit(cpumap, i));
Why isn't ctrl->def->cpumask also stored as a virBitmap, at which point this would be a copy operation instead of a hand-rolled loop?
/* We are pressuming we are running between fork/exec of LXC
While you are here, s/pressuming/presuming/
* so use '0' to indicate our own process ID. No threads are * running at this point */ - if (virProcessInfoSetAffinity(0, /* Self */ - cpumap, cpumaplen, maxcpu) < 0) { + if (virProcessInfoSetAffinity(0 /* Self */, cpumap) < 0) { VIR_FREE(cpumap);
Oops - this cannot be VIR_FREE(cpumap)...
return -1; } - VIR_FREE(cpumap); + virBitmapFree(cpumap);
...but must match this change to virBitmapFree(cpumap).
@@ -4044,10 +4046,10 @@ qemudDomainPinEmulator(virDomainPtr dom, virNodeInfo nodeinfo; int ret = -1; qemuDomainObjPrivatePtr priv; - bool canResetting = true; - int pcpu; + bool canResetting = false;
'canResetting' sounds odd. While you are touching this, can you rename it to something saner, like 'doReset'?
+++ b/src/util/processinfo.c
@@ -59,8 +57,10 @@ realloc: }
CPU_ZERO_S(masklen, mask); - for (i = 0 ; i < maxcpu ; i++) { - if (VIR_CPU_USABLE(map, maplen, 0, i)) + for (i = 0 ; i < virBitmapSize(map); i++) { + if (virBitmapGetBit(map, i, &set) < 0) + return -1; + if (set) CPU_SET_S(i, masklen, mask);
Another case where virBitmap should do this in a single function call, rather than you rolling the loop. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

--- src/conf/domain_conf.c | 24 +++++----------- src/conf/domain_conf.h | 2 +- src/lxc/lxc_controller.c | 7 +++-- src/parallels/parallels_driver.c | 2 +- src/qemu/qemu_cgroup.c | 7 ++--- src/qemu/qemu_cgroup.h | 2 +- src/qemu/qemu_driver.c | 58 ++++++++++---------------------------- src/qemu/qemu_process.c | 34 +++++++++++----------- 8 files changed, 51 insertions(+), 85 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2f496fa..be4c9db 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1661,7 +1661,7 @@ void virDomainDefFree(virDomainDefPtr def) virDomainVcpuPinDefFree(def->cputune.vcpupin, def->cputune.nvcpupin); - VIR_FREE(def->numatune.memory.nodemask); + virBitmapFree(def->numatune.memory.nodemask); virSysinfoDefFree(def->sysinfo); @@ -8439,19 +8439,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, nodeset = virXMLPropString(cur, "nodeset"); if (nodeset) { - char *set = nodeset; - int nodemasklen = VIR_DOMAIN_CPUMASK_LEN; - - if (VIR_ALLOC_N(def->numatune.memory.nodemask, - nodemasklen) < 0) { - virReportOOMError(); - goto error; - } - - /* "nodeset" uses the same syntax as "cpuset". */ - if (virDomainCpuSetParse(set, 0, - def->numatune.memory.nodemask, - nodemasklen) < 0) { + if (virBitmapParse(nodeset, + 0, + &def->numatune.memory.nodemask, + VIR_DOMAIN_CPUMASK_LEN) < 0) { VIR_FREE(nodeset); goto error; } @@ -8493,7 +8484,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, /* Ignore 'nodeset' if 'placement' is 'auto' finally */ if (placement_mode == VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_AUTO) - VIR_FREE(def->numatune.memory.nodemask); + virBitmapFree(def->numatune.memory.nodemask); /* Copy 'placement' of <numatune> to <vcpu> if its 'placement' * is not specified and 'placement' of <numatune> is specified. @@ -13129,8 +13120,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (def->numatune.memory.placement_mode == VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC) { - nodemask = virDomainCpuSetFormat(def->numatune.memory.nodemask, - VIR_DOMAIN_CPUMASK_LEN); + nodemask = virBitmapFormat(def->numatune.memory.nodemask); if (nodemask == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to format nodeset for " diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index ba05fde..7fb1c82 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1545,7 +1545,7 @@ typedef struct _virDomainNumatuneDef virDomainNumatuneDef; typedef virDomainNumatuneDef *virDomainNumatuneDefPtr; struct _virDomainNumatuneDef { struct { - char *nodemask; + virBitmapPtr nodemask; int mode; int placement_mode; /* enum virDomainNumatuneMemPlacementMode */ } memory; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index d6298b0..4b0ceb8 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -402,6 +402,7 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) int i = 0; int maxnode = 0; bool warned = false; + bool nodePresent = false; if (!ctrl->def->numatune.memory.nodemask) return 0; @@ -418,8 +419,10 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (ctrl->def->numatune.memory.nodemask[i]) { + for (i = 0; i < virBitmapSize(ctrl->def->numatune.memory.nodemask); i++) { + if (virBitmapGetBit(ctrl->def->numatune.memory.nodemask, i, &nodePresent) < 0) + return -1; + if (nodePresent) { if (i > NUMA_NUM_NODES) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Host cannot support NUMA node %d"), i); diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 06a75b3..f6fa64a 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -1428,7 +1428,7 @@ parallelsApplyChanges(virDomainObjPtr dom, virDomainDefPtr new) if (old->numatune.memory.mode != new->numatune.memory.mode || old->numatune.memory.placement_mode != new->numatune.memory.placement_mode || - !STREQ_NULLABLE(old->numatune.memory.nodemask, new->numatune.memory.nodemask)) { + !virBitmapCmp(old->numatune.memory.nodemask, new->numatune.memory.nodemask)) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("numa parameters are not supported " diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index f093b75..9e59334 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -195,7 +195,7 @@ int qemuSetupHostUsbDeviceCgroup(usbDevice *dev ATTRIBUTE_UNUSED, int qemuSetupCgroup(struct qemud_driver *driver, virDomainObjPtr vm, - char *nodemask) + virBitmapPtr nodemask) { virCgroupPtr cgroup = NULL; int rc; @@ -412,10 +412,9 @@ int qemuSetupCgroup(struct qemud_driver *driver, char *mask = NULL; if (vm->def->numatune.memory.placement_mode == VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_AUTO) - mask = virDomainCpuSetFormat(nodemask, VIR_DOMAIN_CPUMASK_LEN); + mask = virBitmapFormat(nodemask); else - mask = virDomainCpuSetFormat(vm->def->numatune.memory.nodemask, - VIR_DOMAIN_CPUMASK_LEN); + mask = virBitmapFormat(vm->def->numatune.memory.nodemask); if (!mask) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to convert memory nodemask")); diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h index 04f70a1..1de4856 100644 --- a/src/qemu/qemu_cgroup.h +++ b/src/qemu/qemu_cgroup.h @@ -49,7 +49,7 @@ int qemuSetupHostUsbDeviceCgroup(usbDevice *dev, void *opaque); int qemuSetupCgroup(struct qemud_driver *driver, virDomainObjPtr vm, - char *nodemask); + virBitmapPtr nodemask); int qemuSetupCgroupVcpuBW(virCgroupPtr cgroup, unsigned long long period, long long quota); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index cb7b156..0452a62 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7565,18 +7565,12 @@ qemuDomainSetNumaParameters(virDomainPtr dom, } } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) { int rc; - char *nodeset = NULL; + virBitmapPtr nodeset = NULL; char *nodeset_str = NULL; - if (VIR_ALLOC_N(nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - ret = -1; - goto cleanup; - }; - - if (virDomainCpuSetParse(params[i].value.s, - 0, nodeset, - VIR_DOMAIN_CPUMASK_LEN) < 0) { + if (virBitmapParse(params[i].value.s, + 0, &nodeset, + VIR_DOMAIN_CPUMASK_LEN) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to parse nodeset")); ret = -1; @@ -7589,17 +7583,16 @@ qemuDomainSetNumaParameters(virDomainPtr dom, virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("change of nodeset for running domain " "requires strict numa mode")); - VIR_FREE(nodeset); + virBitmapFree(nodeset); ret = -1; continue; } /* Ensure the cpuset string is formated before passing to cgroup */ - if (!(nodeset_str = virDomainCpuSetFormat(nodeset, - VIR_DOMAIN_CPUMASK_LEN))) { + if (!(nodeset_str = virBitmapFormat(nodeset))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to format nodeset")); - VIR_FREE(nodeset); + virBitmapFree(nodeset); ret = -1; continue; } @@ -7607,7 +7600,7 @@ qemuDomainSetNumaParameters(virDomainPtr dom, if ((rc = virCgroupSetCpusetMems(group, nodeset_str) != 0)) { virReportSystemError(-rc, "%s", _("unable to set numa tunable")); - VIR_FREE(nodeset); + virBitmapFree(nodeset); VIR_FREE(nodeset_str); ret = -1; continue; @@ -7616,40 +7609,22 @@ qemuDomainSetNumaParameters(virDomainPtr dom, /* update vm->def here so that dumpxml can read the new * values from vm->def. */ - if (!vm->def->numatune.memory.nodemask) { - if (VIR_ALLOC_N(vm->def->numatune.memory.nodemask, - VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - VIR_FREE(nodeset); - ret = -1; - goto cleanup; - } - } else { - VIR_FREE(vm->def->numatune.memory.nodemask); - } + virBitmapFree(vm->def->numatune.memory.nodemask); - vm->def->numatune.memory.nodemask = nodeset; vm->def->numatune.memory.placement_mode = VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC; + vm->def->numatune.memory.nodemask = virBitmapCopy(nodeset); } if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - if (!persistentDef->numatune.memory.nodemask) { - if (VIR_ALLOC_N(persistentDef->numatune.memory.nodemask, - VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - VIR_FREE(nodeset); - ret = -1; - goto cleanup; - } - } else { - VIR_FREE(persistentDef->numatune.memory.nodemask); - } + virBitmapFree(persistentDef->numatune.memory.nodemask); persistentDef->numatune.memory.nodemask = nodeset; persistentDef->numatune.memory.placement_mode = VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC; + nodeset = NULL; } + virBitmapFree(nodeset); } } @@ -7744,11 +7719,8 @@ qemuDomainGetNumaParameters(virDomainPtr dom, case 1: /* fill numa nodeset here */ if (flags & VIR_DOMAIN_AFFECT_CONFIG) { - char *mask = persistentDef->numatune.memory.nodemask; - if (mask) - nodeset = virDomainCpuSetFormat(mask, - VIR_DOMAIN_CPUMASK_LEN); - else + nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask); + if (!nodeset) nodeset = strdup(""); } else { rc = virCgroupGetCpusetMems(group, &nodeset); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d4baaa5..491ae77 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -63,6 +63,7 @@ #include "uuid.h" #include "virtime.h" #include "virnetdevtap.h" +#include "bitmap.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -1690,7 +1691,7 @@ qemuProcessDetectVcpuPIDs(struct qemud_driver *driver, #if HAVE_NUMACTL static int qemuProcessInitNumaMemoryPolicy(virDomainObjPtr vm, - const char *nodemask) + virBitmapPtr nodemask) { nodemask_t mask; int mode = -1; @@ -1700,7 +1701,8 @@ qemuProcessInitNumaMemoryPolicy(virDomainObjPtr vm, int maxnode = 0; bool warned = false; virDomainNumatuneDef numatune = vm->def->numatune; - const char *tmp_nodemask = NULL; + virBitmapPtr tmp_nodemask = NULL; + bool result; if (numatune.memory.placement_mode == VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC) { @@ -1725,8 +1727,10 @@ qemuProcessInitNumaMemoryPolicy(virDomainObjPtr vm, maxnode = numa_max_node() + 1; /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (tmp_nodemask[i]) { + for (i = 0; i < virBitmapSize(tmp_nodemask); i++) { + if (virBitmapGetBit(tmp_nodemask, i, &result) < 0) + return -1; + if (result) { if (i > NUMA_NUM_NODES) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Host cannot support NUMA node %d"), i); @@ -1834,7 +1838,7 @@ qemuGetNumadAdvice(virDomainDefPtr def ATTRIBUTE_UNUSED) static int qemuProcessInitCpuAffinity(struct qemud_driver *driver, virDomainObjPtr vm, - const char *nodemask) + virBitmapPtr nodemask) { int ret = -1; int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN; @@ -1864,7 +1868,10 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, for (i = 0; i < driver->caps->host.nnumaCell; i++) { int j; int cur_ncpus = driver->caps->host.numaCell[i]->ncpus; - if (nodemask[i]) { + bool result; + if (virBitmapGetBit(nodemask, i, &result) < 0) + goto cleanup; + if (result) { for (j = 0; j < cur_ncpus; j++) ignore_value(virBitmapSetBit(cpumap, driver->caps->host.numaCell[i]->cpus[j])); @@ -2593,7 +2600,7 @@ struct qemuProcessHookData { virConnectPtr conn; virDomainObjPtr vm; struct qemud_driver *driver; - char *nodemask; + virBitmapPtr nodemask; }; static int qemuProcessHook(void *data) @@ -3350,7 +3357,7 @@ int qemuProcessStart(virConnectPtr conn, unsigned long cur_balloon; int i; char *nodeset = NULL; - char *nodemask = NULL; + virBitmapPtr nodemask = NULL; unsigned int stop_flags; /* Okay, these are just internal flags, @@ -3547,13 +3554,8 @@ int qemuProcessStart(virConnectPtr conn, VIR_DEBUG("Nodeset returned from numad: %s", nodeset); - if (VIR_ALLOC_N(nodemask, VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (virDomainCpuSetParse(nodeset, 0, nodemask, - VIR_DOMAIN_CPUMASK_LEN) < 0) + if (virBitmapParse(nodeset, 0, &nodemask, + VIR_DOMAIN_CPUMASK_LEN) < 0) goto cleanup; } hookData.nodemask = nodemask; @@ -3882,7 +3884,7 @@ cleanup: * if we failed to initialize the now running VM. kill it off and * pretend we never started it */ VIR_FREE(nodeset); - VIR_FREE(nodemask); + virBitmapFree(nodemask); virCommandFree(cmd); VIR_FORCE_CLOSE(logfile); qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, stop_flags); -- 1.7.10.2

On 08/30/2012 02:55 AM, Hu Tao wrote:
+++ b/src/lxc/lxc_controller.c @@ -402,6 +402,7 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) int i = 0; int maxnode = 0; bool warned = false; + bool nodePresent = false;
if (!ctrl->def->numatune.memory.nodemask) return 0; @@ -418,8 +419,10 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl)
/* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (ctrl->def->numatune.memory.nodemask[i]) { + for (i = 0; i < virBitmapSize(ctrl->def->numatune.memory.nodemask); i++) { + if (virBitmapGetBit(ctrl->def->numatune.memory.nodemask, i, &nodePresent) < 0) + return -1; + if (nodePresent) {
If the bitmap is sparse, this argues that we might want a new helper function: /* If bit is -1, find the first set bit (if any); otherwise, find the next set bit after the given position. Return -1 if there are no further set bits. */ int virBitmapNextAfter(virBitmapPtr map, int bit); The loop would then be: int i = virBitmapNextAfter(ctrl->def->numatune.memory.nodemask, -1); while (i >= 0) { /* do stuff for bit i */ i = virBitmapNextAfter(ctrl->def->numatune.memory.nodemask, i); }
+++ b/src/parallels/parallels_driver.c @@ -1428,7 +1428,7 @@ parallelsApplyChanges(virDomainObjPtr dom, virDomainDefPtr new)
if (old->numatune.memory.mode != new->numatune.memory.mode || old->numatune.memory.placement_mode != new->numatune.memory.placement_mode || - !STREQ_NULLABLE(old->numatune.memory.nodemask, new->numatune.memory.nodemask)) { + !virBitmapCmp(old->numatune.memory.nodemask, new->numatune.memory.nodemask)) {
Hmm, this usage says we named the function incorrectly. 'cmp' implies <0, 0, >0 for use in qsort; whereas you give only a bool, so I would name it virBitmapEqual(). -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

--- src/conf/domain_conf.c | 24 +++++++++--------------- src/conf/domain_conf.h | 3 +-- src/lxc/lxc_controller.c | 14 ++++++-------- src/parallels/parallels_driver.c | 3 +-- src/qemu/qemu_process.c | 10 ++++------ src/test/test_driver.c | 5 ++++- src/vmx/vmx.c | 28 ++++++++++++++++++---------- 7 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index be4c9db..117e83b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -8303,14 +8303,12 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) { tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt); if (tmp) { - char *set = tmp; - def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN; - if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) { - goto no_memory; - } - if (virDomainCpuSetParse(set, 0, def->cpumask, - def->cpumasklen) < 0) + if (virBitmapParse(tmp, 0, &def->cpumask, + VIR_DOMAIN_CPUMASK_LEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("topology cpuset syntax error")); goto error; + } VIR_FREE(tmp); } } @@ -12894,7 +12892,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, unsigned char *uuid; char uuidstr[VIR_UUID_STRING_BUFLEN]; const char *type = NULL; - int n, allones = 1; + int n; int i; bool blkio = false; @@ -13023,17 +13021,13 @@ virDomainDefFormatInternal(virDomainDefPtr def, " </memoryBacking>\n", NULL); } - for (n = 0 ; n < def->cpumasklen ; n++) - if (def->cpumask[n] != 1) - allones = 0; - virBufferAddLit(buf, " <vcpu"); virBufferAsprintf(buf, " placement='%s'", virDomainCpuPlacementModeTypeToString(def->placement_mode)); - if (!allones) { + + if (def->cpumask && !virBitmapIsAllSet(def->cpumask)) { char *cpumask = NULL; - if ((cpumask = - virDomainCpuSetFormat(def->cpumask, def->cpumasklen)) == NULL) + if ((cpumask = virBitmapFormat(def->cpumask)) == NULL) goto cleanup; virBufferAsprintf(buf, " cpuset='%s'", cpumask); VIR_FREE(cpumask); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7fb1c82..524345e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1599,8 +1599,7 @@ struct _virDomainDef { unsigned short vcpus; unsigned short maxvcpus; int placement_mode; - int cpumasklen; - char *cpumask; + virBitmapPtr cpumask; struct { unsigned long shares; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 4b0ceb8..b2fcabe 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -494,9 +494,9 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) */ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) { - int i, hostcpus, maxcpu = CPU_SETSIZE; + int hostcpus, maxcpu = CPU_SETSIZE; virNodeInfo nodeinfo; - virBitmapPtr cpumap; + virBitmapPtr cpumap, cpumapToSet; VIR_DEBUG("Setting CPU affinity"); @@ -513,12 +513,10 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) if (!cpumap) return -1; + cpumapToSet = cpumap; + if (ctrl->def->cpumask) { - /* XXX why don't we keep 'cpumask' in the libvirt cpumap - * format to start with ?!?! */ - for (i = 0 ; i < maxcpu && i < ctrl->def->cpumasklen ; i++) - if (ctrl->def->cpumask[i]) - ignore_value(virBitmapSetBit(cpumap, i)); + cpumapToSet = ctrl->def->cpumask; } else { /* You may think this is redundant, but we can't assume libvirtd * itself is running on all pCPUs, so we need to explicitly set @@ -531,7 +529,7 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) * so use '0' to indicate our own process ID. No threads are * running at this point */ - if (virProcessInfoSetAffinity(0 /* Self */, cpumap) < 0) { + if (virProcessInfoSetAffinity(0 /* Self */, cpumapToSet) < 0) { VIR_FREE(cpumap); return -1; } diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index f6fa64a..b72e208 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -1407,8 +1407,7 @@ parallelsApplyChanges(virDomainObjPtr dom, virDomainDefPtr new) return -1; } - if (old->cpumasklen != new->cpumasklen || - (memcmp(old->cpumask, new->cpumask, old->cpumasklen))) { + if (!virBitmapCmp(old->cpumask, new->cpumask)) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("changing cpu mask is not supported " diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 491ae77..837bfdd 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1843,7 +1843,7 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, int ret = -1; int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN; virNodeInfo nodeinfo; - virBitmapPtr cpumap; + virBitmapPtr cpumap, cpumapToSet; VIR_DEBUG("Setting CPU affinity"); @@ -1862,6 +1862,8 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, return -1; } + cpumapToSet = cpumap; + if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) { VIR_DEBUG("Set CPU affinity with advisory nodeset from numad"); /* numad returns the NUMA node list, convert it to cpumap */ @@ -1880,11 +1882,7 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver, } else { VIR_DEBUG("Set CPU affinity with specified cpuset"); if (vm->def->cpumask) { - /* XXX why don't we keep 'cpumask' in the libvirt cpumap - * format to start with ?!?! */ - for (i = 0 ; i < maxcpu && i < vm->def->cpumasklen ; i++) - if (vm->def->cpumask[i]) - ignore_value(virBitmapSetBit(cpumap, i)); + cpumapToSet = vm->def->cpumask; } else { /* You may think this is redundant, but we can't assume libvirtd * itself is running on all pCPUs, so we need to explicitly set diff --git a/src/test/test_driver.c b/src/test/test_driver.c index aa4418a..2e2fb67 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -383,6 +383,7 @@ testDomainUpdateVCPU(virConnectPtr conn ATTRIBUTE_UNUSED, virVcpuInfoPtr info = &privdata->vcpu_infos[vcpu]; unsigned char *cpumap = VIR_GET_CPUMAP(privdata->cpumaps, maplen, vcpu); int j; + bool cpu; memset(info, 0, sizeof(virVcpuInfo)); memset(cpumap, 0, maplen); @@ -394,7 +395,9 @@ testDomainUpdateVCPU(virConnectPtr conn ATTRIBUTE_UNUSED, if (dom->def->cpumask) { for (j = 0; j < maxcpu && j < VIR_DOMAIN_CPUMASK_LEN; ++j) { - if (dom->def->cpumask[j]) { + if (virBitmapGetBit(dom->def->cpumask, j, &cpu) < 0) + return -1; + if (cpu) { VIR_USE_CPU(cpumap, j); info->cpu = j; } diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index db22624..d78a110 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -1235,6 +1235,7 @@ virVMXParseConfig(virVMXContext *ctx, virCapsPtr caps, const char *vmx) int unit; bool hgfs_disabled = true; long long sharedFolder_maxNum = 0; + int cpumasklen; if (ctx->parseFileName == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -1417,9 +1418,10 @@ virVMXParseConfig(virVMXContext *ctx, virCapsPtr caps, const char *vmx) const char *current = sched_cpu_affinity; int number, count = 0; - def->cpumasklen = 0; + cpumasklen = 0; - if (VIR_ALLOC_N(def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) { + def->cpumask = virBitmapAlloc(VIR_DOMAIN_CPUMASK_LEN); + if (!def->cpumask) { virReportOOMError(); goto cleanup; } @@ -1444,11 +1446,11 @@ virVMXParseConfig(virVMXContext *ctx, virCapsPtr caps, const char *vmx) goto cleanup; } - if (number + 1 > def->cpumasklen) { - def->cpumasklen = number + 1; + if (number + 1 > cpumasklen) { + cpumasklen = number + 1; } - def->cpumask[number] = 1; + ignore_value(virBitmapSetBit(def->cpumask, number)); ++count; virSkipSpaces(¤t); @@ -3165,13 +3167,16 @@ virVMXFormatConfig(virVMXContext *ctx, virCapsPtr caps, virDomainDefPtr def, virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus); /* def:cpumask -> vmx:sched.cpu.affinity */ - if (def->cpumasklen > 0) { + if (def->cpumask && virBitmapSize(def->cpumask) > 0) { virBufferAddLit(&buffer, "sched.cpu.affinity = \""); sched_cpu_affinity_length = 0; - for (i = 0; i < def->cpumasklen; ++i) { - if (def->cpumask[i]) { + for (i = 0; i < virBitmapSize(def->cpumask); ++i) { + bool cpu; + if (virBitmapGetBit(def->cpumask, i, &cpu) < 0) + goto cleanup; + if (cpu) { ++sched_cpu_affinity_length; } } @@ -3184,8 +3189,11 @@ virVMXFormatConfig(virVMXContext *ctx, virCapsPtr caps, virDomainDefPtr def, goto cleanup; } - for (i = 0; i < def->cpumasklen; ++i) { - if (def->cpumask[i]) { + for (i = 0; i < virBitmapSize(def->cpumask); ++i) { + bool cpu; + if (virBitmapGetBit(def->cpumask, i, &cpu) < 0) + goto cleanup; + if (cpu) { virBufferAsprintf(&buffer, "%d", i); if (sched_cpu_affinity_length > 1) { -- 1.7.10.2

On 08/30/2012 02:55 AM, Hu Tao wrote:
---
+++ b/src/conf/domain_conf.c @@ -8303,14 +8303,12 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) { tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt); if (tmp) { - char *set = tmp; - def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN; - if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) { - goto no_memory; - } - if (virDomainCpuSetParse(set, 0, def->cpumask, - def->cpumasklen) < 0) + if (virBitmapParse(tmp, 0, &def->cpumask, + VIR_DOMAIN_CPUMASK_LEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("topology cpuset syntax error"));
Internal error is the wrong category; this fits better as VIR_ERR_XML_ERROR. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

--- src/conf/cpu_conf.c | 17 ++++++----------- src/conf/cpu_conf.h | 3 ++- src/qemu/qemu_command.c | 43 +++++++------------------------------------ 3 files changed, 15 insertions(+), 48 deletions(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 87e9540..9fe93e6 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -83,7 +83,7 @@ virCPUDefFree(virCPUDefPtr def) virCPUDefFreeModel(def); for (i = 0 ; i < def->ncells ; i++) { - VIR_FREE(def->cells[i].cpumask); + virBitmapFree(def->cells[i].cpumask); VIR_FREE(def->cells[i].cpustr); } VIR_FREE(def->cells); @@ -164,11 +164,10 @@ virCPUDefCopy(const virCPUDefPtr cpu) copy->cells[i].cellid = cpu->cells[i].cellid; copy->cells[i].mem = cpu->cells[i].mem; - if (VIR_ALLOC_N(copy->cells[i].cpumask, - VIR_DOMAIN_CPUMASK_LEN) < 0) + copy->cells[i].cpumask = virBitmapCopy(cpu->cells[i].cpumask); + + if (!copy->cells[i].cpumask) goto no_memory; - memcpy(copy->cells[i].cpumask, cpu->cells[i].cpumask, - VIR_DOMAIN_CPUMASK_LEN); if (!(copy->cells[i].cpustr = strdup(cpu->cells[i].cpustr))) goto no_memory; @@ -454,7 +453,6 @@ virCPUDefParseXML(const xmlNodePtr node, for (i = 0 ; i < n ; i++) { char *cpus, *memory; - int cpumasklen = VIR_DOMAIN_CPUMASK_LEN; int ret, ncpus = 0; def->cells[i].cellid = i; @@ -466,11 +464,8 @@ virCPUDefParseXML(const xmlNodePtr node, } def->cells[i].cpustr = cpus; - if (VIR_ALLOC_N(def->cells[i].cpumask, cpumasklen) < 0) - goto no_memory; - - ncpus = virDomainCpuSetParse(cpus, 0, def->cells[i].cpumask, - cpumasklen); + ncpus = virBitmapParse(cpus, 0, &def->cells[i].cpumask, + VIR_DOMAIN_CPUMASK_LEN); if (ncpus <= 0) goto error; def->cells_cpus += ncpus; diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 601e208..4e03fd2 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -27,6 +27,7 @@ # include "util.h" # include "buf.h" # include "xml.h" +# include "bitmap.h" # define VIR_CPU_VENDOR_ID_LENGTH 12 @@ -92,7 +93,7 @@ typedef struct _virCellDef virCellDef; typedef virCellDef *virCellDefPtr; struct _virCellDef { int cellid; - char *cpumask; /* CPUs that are part of this node */ + virBitmapPtr cpumask; /* CPUs that are part of this node */ char *cpustr; /* CPUs stored in string form for dumpxml */ unsigned int mem; /* Node memory in kB */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8c32a4d..f4ec0c6 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4252,54 +4252,25 @@ qemuBuildSmpArgStr(const virDomainDefPtr def, return virBufferContentAndReset(&buf); } -static void -qemuBuildNumaCPUArgStr(char *cpumask, virBufferPtr buf) -{ - int i, first, last; - int cpuSet = 0; - - first = last = 0; - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (cpumask[i]) { - if (cpuSet) { - last = i; - } else { - first = last = i; - cpuSet = 1; - } - } else { - if (!cpuSet) - continue; - if (first == last) - virBufferAsprintf(buf, "%d,", first); - else - virBufferAsprintf(buf, "%d-%d,", first, last); - cpuSet = 0; - } - } - - if (cpuSet) { - if (first == last) - virBufferAsprintf(buf, "%d,", first); - else - virBufferAsprintf(buf, "%d-%d,", first, last); - } -} - static int qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd) { int i; virBuffer buf = VIR_BUFFER_INITIALIZER; + char *cpumask; for (i = 0; i < def->cpu->ncells; i++) { virCommandAddArg(cmd, "-numa"); virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid); virBufferAddLit(&buf, ",cpus="); - qemuBuildNumaCPUArgStr(def->cpu->cells[i].cpumask, &buf); + cpumask = virBitmapFormat(def->cpu->cells[i].cpumask); + if (cpumask) { + virBufferAsprintf(&buf, "%s", cpumask); + VIR_FREE(cpumask); + } def->cpu->cells[i].mem = VIR_DIV_UP(def->cpu->cells[i].mem, 1024) * 1024; - virBufferAsprintf(&buf, "mem=%d", def->cpu->cells[i].mem / 1024); + virBufferAsprintf(&buf, ",mem=%d", def->cpu->cells[i].mem / 1024); if (virBufferError(&buf)) goto error; -- 1.7.10.2

--- src/nodeinfo.c | 25 ++++++++++++------------- src/nodeinfo.h | 2 +- src/qemu/qemu_driver.c | 19 ++++++++++++------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/nodeinfo.c b/src/nodeinfo.c index e3d4a24..013eb4a 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -737,29 +737,28 @@ cleanup: * and max cpu is 7. The map file shows 0-4,6-7. This function parses * it and returns cpumap. */ -static char * +static virBitmapPtr linuxParseCPUmap(int *max_cpuid, const char *path) { - char *map = NULL; + virBitmapPtr map = NULL; char *str = NULL; int max_id = 0, i; + bool set = false; if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0) { virReportOOMError(); goto error; } - if (VIR_ALLOC_N(map, VIR_DOMAIN_CPUMASK_LEN) < 0) { - virReportOOMError(); - goto error; - } - if (virDomainCpuSetParse(str, 0, map, - VIR_DOMAIN_CPUMASK_LEN) < 0) { + if (virBitmapParse(str, 0, &map, + VIR_DOMAIN_CPUMASK_LEN) < 0) { goto error; } - for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { - if (map[i]) { + for (i = 0; i < virBitmapSize(map); i++) { + if (virBitmapGetBit(map, i, &set) < 0) + goto error; + if (set) { max_id = i; } } @@ -770,7 +769,7 @@ linuxParseCPUmap(int *max_cpuid, const char *path) error: VIR_FREE(str); - VIR_FREE(map); + virBitmapFree(map); return NULL; } #endif @@ -909,14 +908,14 @@ int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED, #endif } -char * +virBitmapPtr nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED, int *max_id ATTRIBUTE_UNUSED, const char *mapname ATTRIBUTE_UNUSED) { #ifdef __linux__ char *path; - char *cpumap; + virBitmapPtr cpumap; if (virAsprintf(&path, SYSFS_SYSTEM_PATH "/cpu/%s", mapname) < 0) { virReportOOMError(); diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 12090e2..1a2b0af 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -46,7 +46,7 @@ int nodeGetCellsFreeMemory(virConnectPtr conn, int maxCells); unsigned long long nodeGetFreeMemory(virConnectPtr conn); -char *nodeGetCPUmap(virConnectPtr conn, +virBitmapPtr nodeGetCPUmap(virConnectPtr conn, int *max_id, const char *mapname); #endif /* __VIR_NODEINFO_H__*/ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0452a62..0e4a878 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13535,8 +13535,8 @@ qemuDomainGetPercpuStats(virDomainPtr domain, int start_cpu, unsigned int ncpus) { - char *map = NULL; - char *map2 = NULL; + virBitmapPtr map = NULL; + virBitmapPtr map2 = NULL; int rv = -1; int i, max_id; char *pos; @@ -13548,6 +13548,7 @@ qemuDomainGetPercpuStats(virDomainPtr domain, virTypedParameterPtr ent; int param_idx; unsigned long long cpu_time; + bool result; /* return the number of supported params */ if (nparams == 0 && ncpus != 0) @@ -13583,7 +13584,9 @@ qemuDomainGetPercpuStats(virDomainPtr domain, max_id = start_cpu + ncpus - 1; for (i = 0; i <= max_id; i++) { - if (!map[i]) { + if (virBitmapGetBit(map, i, &result) < 0) + goto cleanup; + if (!result) { cpu_time = 0; } else if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -13615,7 +13618,7 @@ qemuDomainGetPercpuStats(virDomainPtr domain, /* Check that the mapping of online cpus didn't change mid-parse. */ map2 = nodeGetCPUmap(domain->conn, &max_id, "present"); - if (!map2 || memcmp(map, map2, VIR_DOMAIN_CPUMASK_LEN) != 0) { + if (!map2 || !virBitmapCmp(map, map2)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("the set of online cpus changed while reading")); goto cleanup; @@ -13623,7 +13626,9 @@ qemuDomainGetPercpuStats(virDomainPtr domain, sum_cpu_pos = sum_cpu_time; for (i = 0; i <= max_id; i++) { - if (!map[i]) + if (virBitmapGetBit(map, i, &result) < 0) + goto cleanup; + if (!result) cpu_time = 0; else cpu_time = *(sum_cpu_pos++); @@ -13641,8 +13646,8 @@ qemuDomainGetPercpuStats(virDomainPtr domain, cleanup: VIR_FREE(sum_cpu_time); VIR_FREE(buf); - VIR_FREE(map); - VIR_FREE(map2); + virBitmapFree(map); + virBitmapFree(map2); return rv; } -- 1.7.10.2

On 08/30/2012 02:55 AM, Hu Tao wrote:
--- src/nodeinfo.c | 25 ++++++++++++------------- src/nodeinfo.h | 2 +- src/qemu/qemu_driver.c | 19 ++++++++++++------- 3 files changed, 25 insertions(+), 21 deletions(-)
+++ b/src/nodeinfo.h @@ -46,7 +46,7 @@ int nodeGetCellsFreeMemory(virConnectPtr conn, int maxCells); unsigned long long nodeGetFreeMemory(virConnectPtr conn);
-char *nodeGetCPUmap(virConnectPtr conn, +virBitmapPtr nodeGetCPUmap(virConnectPtr conn, int *max_id, const char *mapname);
Indentation is now off. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

virBitmap is recommanded to store cpuset info, and virBitmapFormat/virBitmapParse can do the format/parse jobs. --- src/conf/domain_conf.c | 196 ---------------------------------------------- src/conf/domain_conf.h | 7 -- src/libvirt_private.syms | 2 - 3 files changed, 205 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 117e83b..b501ae2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -40,7 +40,6 @@ #include "uuid.h" #include "util.h" #include "buf.h" -#include "c-ctype.h" #include "logging.h" #include "nwfilter_conf.h" #include "storage_file.h" @@ -10757,201 +10756,6 @@ int virDomainDefAddImplicitControllers(virDomainDefPtr def) return 0; } - -/************************************************************************ - * * - * Parser and converter for the CPUset strings used in libvirt * - * * - ************************************************************************/ -/** - * virDomainCpuNumberParse - * @str: pointer to the char pointer used - * @maxcpu: maximum CPU number allowed - * - * Parse a CPU number - * - * Returns the CPU number or -1 in case of error. @str will be - * updated to skip the number. - */ -static int -virDomainCpuNumberParse(const char **str, int maxcpu) -{ - int ret = 0; - const char *cur = *str; - - if (!c_isdigit(*cur)) - return -1; - - while (c_isdigit(*cur)) { - ret = ret * 10 + (*cur - '0'); - if (ret >= maxcpu) - return -1; - cur++; - } - *str = cur; - return ret; -} - -/** - * virDomainCpuSetFormat: - * @conn: connection - * @cpuset: pointer to a char array for the CPU set - * @maxcpu: number of elements available in @cpuset - * - * Serialize the cpuset to a string - * - * Returns the new string NULL in case of error. The string needs to be - * freed by the caller. - */ -char * -virDomainCpuSetFormat(char *cpuset, int maxcpu) -{ - virBuffer buf = VIR_BUFFER_INITIALIZER; - int start, cur; - int first = 1; - - if (!cpuset || maxcpu <= 0 || maxcpu > 100000) - return NULL; - - cur = 0; - start = -1; - while (cur < maxcpu) { - if (cpuset[cur]) { - if (start == -1) - start = cur; - } else if (start != -1) { - if (!first) - virBufferAddLit(&buf, ","); - else - first = 0; - if (cur == start + 1) - virBufferAsprintf(&buf, "%d", start); - else - virBufferAsprintf(&buf, "%d-%d", start, cur - 1); - start = -1; - } - cur++; - } - if (start != -1) { - if (!first) - virBufferAddLit(&buf, ","); - if (maxcpu == start + 1) - virBufferAsprintf(&buf, "%d", start); - else - virBufferAsprintf(&buf, "%d-%d", start, maxcpu - 1); - } - - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return NULL; - } - - return virBufferContentAndReset(&buf); -} - -/** - * virDomainCpuSetParse: - * @conn: connection - * @str: a CPU set string pointer - * @sep: potential character used to mark the end of string if not 0 - * @cpuset: pointer to a char array for the CPU set - * @maxcpu: number of elements available in @cpuset - * - * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset - * to 1, and 0 otherwise. The syntax allows comma separated entries; each - * can be either a CPU number, ^N to unset that CPU, or N-M for ranges. - * - * Returns the number of CPU found in that set, or -1 in case of error. - * @cpuset is modified accordingly to the value parsed. - */ -int -virDomainCpuSetParse(const char *str, char sep, - char *cpuset, int maxcpu) -{ - const char *cur; - int ret = 0; - int i, start, last; - int neg = 0; - - if (!str || !cpuset || maxcpu <= 0 || maxcpu > 100000) - return -1; - - cur = str; - virSkipSpaces(&cur); - if (*cur == 0) - goto parse_error; - - /* initialize cpumap to all 0s */ - for (i = 0; i < maxcpu; i++) - cpuset[i] = 0; - ret = 0; - - while (*cur != 0 && *cur != sep) { - /* - * 3 constructs are allowed: - * - N : a single CPU number - * - N-M : a range of CPU numbers with N < M - * - ^N : remove a single CPU number from the current set - */ - if (*cur == '^') { - cur++; - neg = 1; - } - - if (!c_isdigit(*cur)) - goto parse_error; - start = virDomainCpuNumberParse(&cur, maxcpu); - if (start < 0) - goto parse_error; - virSkipSpaces(&cur); - if (*cur == ',' || *cur == 0 || *cur == sep) { - if (neg) { - if (cpuset[start] == 1) { - cpuset[start] = 0; - ret--; - } - } else { - if (cpuset[start] == 0) { - cpuset[start] = 1; - ret++; - } - } - } else if (*cur == '-') { - if (neg) - goto parse_error; - cur++; - virSkipSpaces(&cur); - last = virDomainCpuNumberParse(&cur, maxcpu); - if (last < start) - goto parse_error; - for (i = start; i <= last; i++) { - if (cpuset[i] == 0) { - cpuset[i] = 1; - ret++; - } - } - virSkipSpaces(&cur); - } - if (*cur == ',') { - cur++; - virSkipSpaces(&cur); - neg = 0; - } else if (*cur == 0 || *cur == sep) { - break; - } else { - goto parse_error; - } - } - return ret; - - parse_error: - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("topology cpuset syntax error")); - return -1; -} - - /* Check if vcpupin with same vcpuid already exists. * Return 1 if exists, 0 if not. */ int diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 524345e..9386438 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1878,13 +1878,6 @@ int virDomainDefFormatInternal(virDomainDefPtr def, int virDomainDefCompatibleDevice(virDomainDefPtr def, virDomainDeviceDefPtr dev); -int virDomainCpuSetParse(const char *str, - char sep, - char *cpuset, - int maxcpu); -char *virDomainCpuSetFormat(char *cpuset, - int maxcpu); - int virDomainVcpuPinAdd(virDomainVcpuPinDefPtr *vcpupin_list, int *nvcpupin, unsigned char *cpumap, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9c27218..b3e9faf 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -305,8 +305,6 @@ virDomainControllerRemove; virDomainControllerTypeToString; virDomainCpuPlacementModeTypeFromString; virDomainCpuPlacementModeTypeToString; -virDomainCpuSetFormat; -virDomainCpuSetParse; virDomainDefAddImplicitControllers; virDomainDefCheckABIStability; virDomainDefClearDeviceAliases; -- 1.7.10.2

On 08/30/2012 02:55 AM, Hu Tao wrote:
In many places we store bitmap info in a chunk of data (pointed to by a char *), and have redundant codes to set/unset bits. This patch extends virBitmap, and convert those codes to use virBitmap in subsquent patches.
s/subsquent/subsequent/ The overall series sounds nice. There was no cover letter (0/8) to the series, so it's a bit harder to track the overall diffstat, although it looks like you have a net reduction of lines based on previewing individual patches later in the series - always a nice result. And having nice interfaces here means that later patches should still apply even if I make you change the internals of this patch. Overall, I think we can get this series into shape for 0.10.2.
--- .gitignore | 1 + src/libvirt_private.syms | 10 ++ src/util/bitmap.c | 391 +++++++++++++++++++++++++++++++++++++++++++++- src/util/bitmap.h | 23 +++ tests/Makefile.am | 8 +- tests/virbitmaptest.c | 134 ++++++++++++++++ 6 files changed, 562 insertions(+), 5 deletions(-) create mode 100644 tests/virbitmaptest.c
diff --git a/.gitignore b/.gitignore index 5041ddf..9aaa1f5 100644 --- a/.gitignore +++ b/.gitignore @@ -155,6 +155,7 @@ /tests/storagebackendsheepdogtest /tests/utiltest /tests/viratomictest +/tests/virbitmaptest /tests/virauthconfigtest
Needs to be sorted, otherwise the next person running ./autogen.sh on a fresh checkout will have a spurious difference.
+++ b/src/util/bitmap.c @@ -33,15 +33,17 @@ #include "bitmap.h" #include "memory.h" #include "buf.h" +#include "util.h" +#include "c-ctype.h"
struct _virBitmap { size_t size; - unsigned long *map; + unsigned char *map;
NACK to this hunk; iterating over longs is more efficient than iterating over char. It means the conversion from a char* data will have to be a bit more involved, but that's life.
};
-#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned long) * CHAR_BIT) +#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned char) * CHAR_BIT)
sizeof(unsigned char) == 1, by definition; I always question use of code like this (and if you follow my earlier comment of keeping things with long* rather than char*, then my objection on this hunk becomes irrelevant).
+/* Helper function. caller must ensure b < bitmap->size */ +static bool bitmapIsset(virBitmapPtr bitmap, size_t b)
s/bitmapIsset/virBitmapIsSet/ - we want to use consistent naming, even for static functions.
@@ -168,7 +176,7 @@ char *virBitmapString(virBitmapPtr bitmap) VIR_BITMAP_BITS_PER_UNIT;
while (sz--) { - virBufferAsprintf(&buf, "%0*lx", + virBufferAsprintf(&buf, "%0*hx",
char* would be hhx, not hx (but again, I want to keep this at lx).
+/** + * virBitmapFormat: + * @bitmap: the bitmap + * + * This function is the counterpart of virBitmapParse. This function creates + * a human-readable string representing the bits in bitmap. + * + * See virBitmapParse for the format of @str. + * + * Returns the string on success or NULL otherwise. Caller should call + * VIR_FREE to free the string. + */ +char *virBitmapFormat(virBitmapPtr bitmap) +{ + virBuffer buf =VIR_BUFFER_INITIALIZER;
space after =
+/** + * virBitmapParse: + * @str: points to a string representing a human-readable bitmap + * @bitmap: a bitmap created from @str + * @bitmapSize: the upper limit of num of bits in created bitmap + * + * This function is the counterpart of virBitmapFormat. This function creates + * a bitmap, in which bits are set according to the content of @str. + * + * @str is a comma separated string of fields N, which means a number of bit + * to set, and ^N, which means to unset the bit, and N-M for ranges of bits + * to set. + * + * Returns the number of bits set in @bitmap, or -1 in case of error. + */ + +int virBitmapParse(const char *str, + char sep, + virBitmapPtr *bitmap, + size_t bitmapSize) +{ + int ret = 0; + int neg = 0;
s/int/bool/; s/0/false/ for all uses of neg in this function
+/** + * virBitmapAllocFromData: + * @data: the data + * @len: len of @data in byte
length of @data in bytes
+ * + * Allocate a bitmap from a chunk of data containing bits + * information + * + * Returns a pointer to the allocated bitmap or NULL if + * memory cannot be allocated. + */ +virBitmapPtr virBitmapAllocFromData(void *data, int len) +{ + virBitmapPtr bitmap; + + bitmap = virBitmapAlloc(len * CHAR_BIT); + if (!bitmap) + return NULL; + + memcpy(bitmap->map, data, len);
Here's where you need to do some work to keep virBitmap using longs.
+/** + * virBitmapToData: + * @data: the data + * @len: len of @data in byte + * + * Convert a bitmap to a chunk of data containing bits information. + * Data consists of sequential bytes, with lower bytes containing + * lower bits. + * + * Returns 0 on success, -1 otherwise. + */ +int virBitmapToData(virBitmapPtr bitmap, char **data, int *dataLen) +{ + size_t sz; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT;
Hmm; we seem to be recomputing this in a lot of code; maybe it's better to compute it once at virBitmap creation and make the struct one member larger.
+ + if (VIR_ALLOC_N(*data, sz) < 0) + return -1; + + memcpy(*data, bitmap->map, sz);
And another conversion needed, this time from long to char.
+/** + * virBitmapCmp: + * @b1: bitmap 1 + * @b2: bitmap 2 + * + * Compares two bitmaps. Returns true if two bitmaps have exactly + * the same set of bits set, otherwise false.
Mention specifically that this works even for maps of different lengths, if the longer map has a 0 tail.
+ */ +bool virBitmapCmp(virBitmapPtr b1, virBitmapPtr b2) +{ + virBitmapPtr b; + size_t sz1, sz2, sz; + int i; + + sz1 = (b1->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + sz2 = (b2->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + sz = sz1 < sz2 ? sz1 : sz2; + + for (i = 0; i < sz; i++) { + if (b1->map[i] != b2->map[i]) + return false; + } + + b = sz1 > sz ? b1 : b2; + sz = sz1 > sz ? sz1 : sz2;
Rather than computing 'sz1 > sz ?:' three times, why not: if (b1->size > b2->size) { virBitmapPtr tmp = b1; b1 = b2; b2 = b1; } up front, prior to computing sz1 and sz2, at which point you know that sz1 <= sz2 for the rest of the function.
+/** + * virBitmapSetAll: + * @bitmap: the bitmap + * + * set all bits in @bitmap. + */ +void virBitmapSetAll(virBitmapPtr bitmap) +{
Do we _also_ want virBitmapSetRange(virBitmapPtr bitmap, size_t start, size_t len), for setting a portion of the map?
+ for (i = 0; i < sz; i++) + bitmap->map[i] = -1;
Why not memset()?
+/** + * virBitmapClearAll: + * @bitmap: the bitmap + * + * clear all bits in @bitmap.
Similarly for virBitmapClearRange(virBitmapPtr bitmap, size_t start, size_t len).
+ */ +void virBitmapClearAll(virBitmapPtr bitmap) +{ + int i; + size_t sz; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + for (i = 0; i < sz; i++) + bitmap->map[i] = 0;
Again, memset().
+ * virBitmapIsAllSet: + * @bitmap: the bitmap to check + * + * check if all bits in @bitmap are set. + */ +bool virBitmapIsAllSet(virBitmapPtr bitmap) +{ + int i; + int unusedBits; + size_t sz, tmp; + + sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + unusedBits = sz * VIR_BITMAP_BITS_PER_UNIT - bitmap->size; + + tmp = sz; + if (unusedBits > 0) + tmp = sz - 1; + + for (i = 0; i < tmp; i++) + if (bitmap->map[i] != (unsigned char)-1)
Unnecessary cast (especially if you keep the code with long).
+ return false; + + if (unusedBits > 0) { + if ((bitmap->map[sz - 1] & ((1 << (VIR_BITMAP_BITS_PER_UNIT - unusedBits + 1)) - 1))
s/1 <</1U <</ - need to use unsigned math to guarantee defined results.
+++ b/src/util/bitmap.h @@ -62,4 +62,27 @@ int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) char *virBitmapString(virBitmapPtr bitmap) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+char *virBitmapFormat(virBitmapPtr bitmap);
Quite a few of these need ATTRIBUTE_NONNULL() markings.
+++ b/tests/Makefile.am @@ -92,7 +92,8 @@ test_programs = virshtest sockettest \ viratomictest \ utiltest virnettlscontexttest shunloadtest \ virtimetest viruritest virkeyfiletest \ - virauthconfigtest + virauthconfigtest \ + virbitmaptest
Spacing is off; Makefiles use TAB.
@@ -592,6 +597,7 @@ shunloadtest_SOURCES = \ shunloadtest_LDADD = $(LIB_PTHREAD) shunloadtest_DEPENDENCIES = libshunload.la
+ if WITH_CIL
Spurious whitespace change.
+++ b/tests/virbitmaptest.c
+bool testBit(virBitmapPtr bitmap, unsigned int start, unsigned int end)
Too weak - you are using this to check that all bits in a range have a given value, but for that to work, you need to know what the desired value is as a fourth parameter.
+ if (!testBit(bitmap, 1021, 1023)) + goto error; + + if (testBit(bitmap, 0, 0)) + goto error; + if (testBit(bitmap, 33,49)) + goto error;
That is, in these uses, you really want: if (testBits(bitmap, 1021, 1023, true) < 0 || testBits(bitmap, 33, 49, false) < 0) goto error; -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Hu Tao