New 'update-memory-device' command is introduced which aims on
making it user friendly to change <memory/> device. So far I just
need to change <requested/> so I'm introducing --requested-size
only; but the idea is that this is extensible for other cases
too. For instance, want to change <myElement/>? A new
--my-element argument can be easily introduced.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
docs/manpages/virsh.rst | 30 ++++++++
tools/virsh-domain.c | 161 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 191 insertions(+)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 350ded2026..4c5341d00d 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -4919,6 +4919,36 @@ results as some fields may be autogenerated and thus match devices
other than
expected.
+update-memory-device
+--------------------
+
+**Syntax:**
+
+::
+
+ update-memory-device domain [--print-xml] [[--alias alias] | [--node node]]
+ [[--live] [--config] | [--current]]
+ [--requested-size size]
+
+This command finds ``<memory/>`` device inside given *domain*, changes
+requested values and passes updated device XML to daemon. If *--print-xml* is
+specified then the device is not changed, but the updated device XML is printed
+to stdout. If there are more than one ``<memory/>`` devices in *domain* use
+*--alias* or *--node* to select the desired one.
+
+If *--live* is specified, affect a running domain.
+If *--config* is specified, affect the next startup of a persistent guest.
+If *--current* is specified, it is equivalent to either *--live* or
+*--config*, depending on the current state of the guest.
+Both *--live* and *--config* flags may be given, but *--current* is
+exclusive. Not specifying any flag is the same as specifying *--current*.
+
+If *--requested-size* is specified then ``<requested/>`` under memory target is
+changed to requested *size* (as scaled integer, see ``NOTES`` above). It
+defaults to kibibytes if no suffix is provided. The option is valid only for
+``virtio-mem`` memory device model.
+
+
change-media
------------
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 5150c216d7..906654674e 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -8968,6 +8968,161 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
return true;
}
+
+/*
+ * "update-memory-device" command
+ */
+static const vshCmdInfo info_update_memory_device[] = {
+ {.name = "help",
+ .data = N_("update memory device of a domain")
+ },
+ {.name = "desc",
+ .data = N_("Update values of a memory device of a domain")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_update_memory_device[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ VIRSH_COMMON_OPT_DOMAIN_CONFIG,
+ VIRSH_COMMON_OPT_DOMAIN_LIVE,
+ VIRSH_COMMON_OPT_DOMAIN_CURRENT,
+ {.name = "print-xml",
+ .type = VSH_OT_BOOL,
+ .help = N_("print updated memory device XML instead of executing the
change")
+ },
+ {.name = "alias",
+ .type = VSH_OT_STRING,
+ .completer = virshDomainDeviceAliasCompleter,
+ .help = N_("memory device alias")
+ },
+ {.name = "node",
+ .type = VSH_OT_INT,
+ .help = N_("memory device target node")
+ },
+ {.name = "requested-size",
+ .type = VSH_OT_INT,
+ .help = N_("new value of <requested/> size, as scaled integer (default
KiB)")
+ },
+ {.name = NULL}
+};
+
+static int
+virshGetUpdatedMemoryXML(char **updatedMemoryXML,
+ vshControl *ctl,
+ const vshCmd *cmd,
+ virDomainPtr dom,
+ unsigned int flags)
+{
+ const char *alias = NULL;
+ bool nodeOpt = false;
+ unsigned int node = 0;
+ g_autoptr(xmlDoc) doc = NULL;
+ g_autoptr(xmlXPathContext) ctxt = NULL;
+ g_autofree char *xpath = NULL;
+ int nmems;
+ g_autofree xmlNodePtr *mems = NULL;
+ unsigned int domainXMLFlags = 0;
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG)
+ domainXMLFlags |= VIR_DOMAIN_XML_INACTIVE;
+
+ if (virshDomainGetXMLFromDom(ctl, dom, domainXMLFlags, &doc, &ctxt) < 0)
+ return -1;
+
+ nodeOpt = vshCommandOptBool(cmd, "node");
+ if (vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0 ||
+ vshCommandOptUInt(ctl, cmd, "node", &node) < 0) {
+ return -1;
+ }
+
+ if (nodeOpt) {
+ xpath =
g_strdup_printf("/domain/devices/memory[./target/node='%u']", node);
+ } else if (alias) {
+ xpath =
g_strdup_printf("/domain/devices/memory[./alias/@name='%s']", alias);
+ } else {
+ xpath = g_strdup("/domain/devices/memory");
+ }
+
+ nmems = virXPathNodeSet(xpath, ctxt, &mems);
+ if (nmems < 0) {
+ vshSaveLibvirtError();
+ return -1;
+ } else if (nmems == 0) {
+ vshError(ctl, _("no memory device found"));
+ return -1;
+ } else if (nmems > 1) {
+ vshError(ctl, _("multiple memory devices found, use --alias or --node to
select one"));
+ return -1;
+ }
+
+ ctxt->node = mems[0];
+
+ if (vshCommandOptBool(cmd, "requested-size")) {
+ xmlNodePtr requestedSizeNode;
+ g_autofree char *kibibytesStr = NULL;
+ unsigned long long bytes = 0;
+ unsigned long kibibytes = 0;
+
+ if (vshCommandOptScaledInt(ctl, cmd, "requested-size", &bytes,
1024, ULLONG_MAX) < 0)
+ return -1;
+ kibibytes = VIR_DIV_UP(bytes, 1024);
+
+ requestedSizeNode = virXPathNode("./target/requested", ctxt);
+
+ if (!requestedSizeNode) {
+ vshError(ctl, _("virtio-mem device is missing
<requested/>"));
+ return -1;
+ }
+
+ kibibytesStr = g_strdup_printf("%lu", kibibytes);
+ xmlNodeSetContent(requestedSizeNode, BAD_CAST kibibytesStr);
+ }
+
+ if (!(*updatedMemoryXML = virXMLNodeToString(doc, mems[0]))) {
+ vshSaveLibvirtError();
+ return -1;
+ }
+
+ return 0;
+}
+
+static bool
+cmdUpdateMemoryDevice(vshControl *ctl, const vshCmd *cmd)
+{
+ g_autoptr(virshDomain) dom = NULL;
+ bool config = vshCommandOptBool(cmd, "config");
+ bool live = vshCommandOptBool(cmd, "live");
+ bool current = vshCommandOptBool(cmd, "current");
+ g_autofree char *updatedMemoryXML = NULL;
+ unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
+
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+ VSH_EXCLUSIVE_OPTIONS("node", "alias");
+
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ return false;
+
+ if (virshGetUpdatedMemoryXML(&updatedMemoryXML, ctl, cmd, dom, flags) < 0)
+ return false;
+
+ if (vshCommandOptBool(cmd, "print-xml")) {
+ vshPrint(ctl, "%s", updatedMemoryXML);
+ } else {
+ if (virDomainUpdateDeviceFlags(dom, updatedMemoryXML, flags) < 0)
+ return false;
+ }
+
+ return true;
+}
+
+
/*
* "memtune" command
*/
@@ -14748,6 +14903,12 @@ const vshCmdDef domManagementCmds[] = {
.info = info_update_device,
.flags = 0
},
+ {.name = "update-memory-device",
+ .handler = cmdUpdateMemoryDevice,
+ .opts = opts_update_memory_device,
+ .info = info_update_memory_device,
+ .flags = 0
+ },
{.name = "vcpucount",
.handler = cmdVcpucount,
.opts = opts_vcpucount,
--
2.32.0