From 2903534a308150d3317fa181047c4a52fd5357ba Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 10 Jun 2011 15:38:55 +0900 Subject: [PATCH] vcpupin: improve vcpupin definition of virsh vcpupin When using vcpupin command, we have to speficy comma-separated list as cpulist, but this is tedious in case the number of phsycal cpus is large. This patch improves this by introducing special markup "-" and "^" which are similar to XML schema of "cpuset" attribute. The example: # virsh vcpupin Guest 0 0-15,^8 is identical to # virsh vcpupin Guest 0 0,1,2,3,4,5,6,7,9,10,11,12,13,14,15 NOTE: The expression is sequentially evaluated, so "0-15,^8" is not identical to "^8,0-15". Signed-off-by: Taku Izumi --- tools/virsh.c | 129 +++++++++++++++++++++++++++--------------------- tools/virsh.pod | 7 ++- 2 files changed, 78 insertions(+), 58 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index b7b9552b4e..92faffc02c 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2998,8 +2998,9 @@ cmdVcpupin(vshControl *ctl, const vshCmd *cmd) bool ret = true; unsigned char *cpumap; int cpumaplen; - int i; - enum { expect_num, expect_num_or_comma } state; + int i, cpu, lastcpu, maxcpu; + bool unuse = false; + char *cur; int config = vshCommandOptBool(cmd, "config"); int live = vshCommandOptBool(cmd, "live"); int current = vshCommandOptBool(cmd, "current"); @@ -3055,66 +3056,74 @@ cmdVcpupin(vshControl *ctl, const vshCmd *cmd) return false; } - /* Check that the cpulist parameter is a comma-separated list of - * numbers and give an intelligent error message if not. - */ - if (cpulist[0] == '\0') { - vshError(ctl, "%s", _("cpulist: Invalid format. Empty string.")); - virDomainFree (dom); - return false; - } + maxcpu = VIR_NODEINFO_MAXCPUS(nodeinfo); + cpumaplen = VIR_CPU_MAPLEN(maxcpu); + cpumap = vshCalloc(ctl, 0, cpumaplen); - state = expect_num; - for (i = 0; cpulist[i]; i++) { - switch (state) { - case expect_num: - if (!c_isdigit (cpulist[i])) { - vshError(ctl, _("cpulist: %s: Invalid format. Expecting " - "digit at position %d (near '%c')."), - cpulist, i, cpulist[i]); - virDomainFree (dom); - return false; - } - state = expect_num_or_comma; - break; - case expect_num_or_comma: - if (cpulist[i] == ',') - state = expect_num; - else if (!c_isdigit (cpulist[i])) { - vshError(ctl, _("cpulist: %s: Invalid format. Expecting " - "digit or comma at position %d (near '%c')."), - cpulist, i, cpulist[i]); - virDomainFree (dom); - return false; - } + /* Parse cpulist */ + cur = cpulist; + if (*cur == 0) + goto parse_error; + + while (*cur != 0) { + + /* the char '^' denotes exclusive */ + if (*cur == '^') { + cur++; + unuse = true; } - } - if (state == expect_num) { - vshError(ctl, _("cpulist: %s: Invalid format. Trailing comma " - "at position %d."), - cpulist, i); - virDomainFree (dom); - return false; - } - cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); - cpumap = vshCalloc(ctl, 1, cpumaplen); - - do { - unsigned int cpu = atoi(cpulist); - - if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) { - VIR_USE_CPU(cpumap, cpu); - } else { + /* parse physical CPU number */ + if (!c_isdigit(*cur)) + goto parse_error; + cpu = virParseNumber(&cur); + if (cpu < 0) { + goto parse_error; + } + if (cpu >= maxcpu) { vshError(ctl, _("Physical CPU %d doesn't exist."), cpu); - VIR_FREE(cpumap); - virDomainFree(dom); - return false; + goto parse_error; } - cpulist = strchr(cpulist, ','); - if (cpulist) - cpulist++; - } while (cpulist); + virSkipSpaces(&cur); + + if ((*cur == ',') || (*cur == 0)) { + if (unuse) { + VIR_UNUSE_CPU(cpumap, cpu); + } else { + VIR_USE_CPU(cpumap, cpu); + } + } else if (*cur == '-') { + /* the char '-' denotes range */ + if (unuse) { + goto parse_error; + } + cur++; + virSkipSpaces(&cur); + /* parse the end of range */ + lastcpu = virParseNumber(&cur); + if (lastcpu < cpu) { + goto parse_error; + } + if (lastcpu >= maxcpu) { + vshError(ctl, _("Physical CPU %d doesn't exist."), maxcpu); + goto parse_error; + } + for (i = cpu; i <= lastcpu; i++) { + VIR_USE_CPU(cpumap, i); + } + virSkipSpaces(&cur); + } + + if (*cur == ',') { + cur++; + virSkipSpaces(&cur); + unuse = false; + } else if (*cur == 0) { + break; + } else { + goto parse_error; + } + } if (flags == -1) { if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0) { @@ -3126,9 +3135,15 @@ cmdVcpupin(vshControl *ctl, const vshCmd *cmd) } } +cleanup: VIR_FREE(cpumap); virDomainFree(dom); return ret; + +parse_error: + vshError(ctl, "%s", _("cpulist: Invalid format.")); + ret = false; + goto cleanup; } /* diff --git a/tools/virsh.pod b/tools/virsh.pod index fa374425d9..b90f37eab7 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -833,13 +833,18 @@ vCPUs, the running time, the affinity to physical processors. I<--current> Pin domain VCPUs to host physical CPUs. The I number must be provided -and I is a comma separated list of physical CPU numbers. +and I is a list of physical CPU numbers. Its syntax is a comma +separated list and a special markup using '-' and '^' (ex. '0-4', '0-3,^2') can +also be allowed. The '-' denotes the range and the '^' denotes exclusive. If I<--live> is specified, affect a running guest. If I<--config> is specified, affect the next boot of a persistent guest. If I<--current> is specified, affect the current guest state. Both I<--live> and I<--config> flags may be given, but I<--current> is exclusive. If no flag is specified, behavior is different depending on hypervisor. +B: The expression is sequentially evaluated, so "0-15,^8" is not identical +to "^8,0-15". + =item B I Output the IP address and port number for the VNC display. If the information