---
tools/virsh-domain.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 16 +++++
2 files changed, 204 insertions(+)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index aab5921..dfbe501 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -4761,6 +4761,193 @@ parse_error:
}
/*
+ * "emulatorpin" command
+ */
+static const vshCmdInfo info_emulatorpin[] = {
+ {"help", N_("control or query domain emulator affinity")},
+ {"desc", N_("Pin domain emulator threads to host physical
CPUs.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_emulatorpin[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
+ {"cpulist", VSH_OT_DATA, VSH_OFLAG_EMPTY_OK,
+ N_("host cpu number(s) to set, or omit option to query")},
+ {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
+ {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
+ {"current", VSH_OT_BOOL, 0, N_("affect current domain")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdEmulatorPin(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom;
+ virNodeInfo nodeinfo;
+ const char *cpulist = NULL;
+ bool ret = true;
+ unsigned char *cpumap = NULL;
+ unsigned char *cpumaps = NULL;
+ size_t cpumaplen;
+ int i, cpu, lastcpu, maxcpu;
+ bool unuse = false;
+ const char *cur;
+ bool config = vshCommandOptBool(cmd, "config");
+ bool live = vshCommandOptBool(cmd, "live");
+ bool current = vshCommandOptBool(cmd, "current");
+ bool query = false; /* Query mode if no cpulist */
+ unsigned int flags = 0;
+
+ if (current) {
+ if (live || config) {
+ vshError(ctl, "%s", _("--current must be specified
exclusively"));
+ return false;
+ }
+ flags = VIR_DOMAIN_AFFECT_CURRENT;
+ } else {
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+ /* neither option is specified */
+ if (!live && !config)
+ flags = -1;
+ }
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ return false;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+ return false;
+
+ if (vshCommandOptString(cmd, "cpulist", &cpulist) < 0) {
+ vshError(ctl, "%s", _("emulatorpin: Missing cpulist."));
+ virDomainFree(dom);
+ return false;
+ }
+ query = !cpulist;
+
+ if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
+ virDomainFree(dom);
+ return false;
+ }
+
+ maxcpu = VIR_NODEINFO_MAXCPUS(nodeinfo);
+ cpumaplen = VIR_CPU_MAPLEN(maxcpu);
+
+ /* Query mode: show CPU affinity information then exit.*/
+ if (query) {
+ /* When query mode and neither "live", "config" nor
"current"
+ * is specified, set VIR_DOMAIN_AFFECT_CURRENT as flags */
+ if (flags == -1)
+ flags = VIR_DOMAIN_AFFECT_CURRENT;
+
+ cpumaps = vshMalloc(ctl, cpumaplen);
+ if (virDomainGetEmulatorPinInfo(dom, cpumaps,
+ cpumaplen, flags) >= 0) {
+ vshPrint(ctl, "%s %s\n", _("emulator:"), _("CPU
Affinity"));
+ vshPrint(ctl, "----------------------------------\n");
+ vshPrint(ctl, " *: ");
+ ret = vshPrintPinInfo(cpumaps, cpumaplen, maxcpu, 0);
+ vshPrint(ctl, "\n");
+ } else {
+ ret = false;
+ }
+ VIR_FREE(cpumaps);
+ goto cleanup;
+ }
+
+ /* Pin mode: pinning emulator threads to specified physical cpus*/
+
+ cpumap = vshCalloc(ctl, cpumaplen, sizeof(cpumap));
+ /* Parse cpulist */
+ cur = cpulist;
+ if (*cur == 0) {
+ goto parse_error;
+ } else if (*cur == 'r') {
+ for (cpu = 0; cpu < maxcpu; cpu++)
+ VIR_USE_CPU(cpumap, cpu);
+ cur = "";
+ }
+
+ while (*cur != 0) {
+
+ /* the char '^' denotes exclusive */
+ if (*cur == '^') {
+ cur++;
+ unuse = true;
+ }
+
+ /* 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);
+ goto parse_error;
+ }
+ 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)
+ flags = VIR_DOMAIN_AFFECT_LIVE;
+
+ if (virDomainPinEmulator(dom, cpumap, cpumaplen, flags) != 0)
+ ret = false;
+
+cleanup:
+ VIR_FREE(cpumap);
+ virDomainFree(dom);
+ return ret;
+
+parse_error:
+ vshError(ctl, "%s", _("cpulist: Invalid format."));
+ ret = false;
+ goto cleanup;
+}
+
+/*
* "setvcpus" command
*/
static const vshCmdInfo info_setvcpus[] = {
@@ -8192,6 +8379,7 @@ const vshCmdDef domManagementCmds[] = {
{"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0},
{"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0},
{"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0},
+ {"emulatorpin", cmdEmulatorPin, opts_emulatorpin, info_emulatorpin, 0},
{"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0},
{NULL, NULL, NULL, NULL, 0}
};
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 35613c4..f5f1ca1 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1614,6 +1614,22 @@ If no flag is specified, behavior is different depending on
hypervisor.
B<Note>: The expression is sequentially evaluated, so "0-15,^8" is
identical to "9-14,0-7,15" but not identical to "^8,0-15".
+=item B<emulatorpin> I<domain> [I<cpulist>] [[I<--live>]
[I<--config>]
+ | [I<--current>]]
+
+Query or change the pinning of domain's emulator threads to host physical
+CPUs.
+
+See B<vcpupin> for I<cpulist>.
+
+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 if I<cpulist> is
present,
+but I<--current> is exclusive.
+If no flag is specified, behavior is different depending on hypervisor.
+
+
=item B<vncdisplay> I<domain>
Output the IP address and port number for the VNC display. If the information
--
1.7.10.2