Provide an user friendly way of modifying 'requested-size' of a
virtio-mem device. New --node and --alias arguments are
introduced but they are needed only if it is not clear which
virtio-mem does user mean.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
docs/manpages/virsh.rst | 6 ++
tools/virsh-domain.c | 126 ++++++++++++++++++++++++++++++++++++----
2 files changed, 122 insertions(+), 10 deletions(-)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 9ef6b68422..c3c8c27a18 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -4098,6 +4098,7 @@ setmem
::
setmem domain size [[--config] [--live] | [--current]]
+ [--virtio [--node NODE] | [--alias ALIAS]]
Change the memory allocation for a guest domain.
If *--live* is specified, perform a memory balloon of a running guest.
@@ -4107,6 +4108,11 @@ If *--current* is specified, it is equivalent to either *--live*
or
Both *--live* and *--config* flags may be given, but *--current* is
exclusive. If no flag is specified, behavior is different depending
on hypervisor.
+If *--virtio* is specified then instead of changing the memory allocation for
+whole domain the individual memory device with virtio model is changed. If
+there is more than one such memory device then *--node* or *--alias* must be
+used to specify the device uniquely. *NODE* refers to the guest NUMA node to
+which the memory device is attached to and *ALIAS* is the device alias.
*size* is a scaled integer (see ``NOTES`` above); it defaults to kibibytes
(blocks of 1024 bytes) unless you provide a suffix (and the older option
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index eeeeaa8639..7d8546d806 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -8992,12 +8992,101 @@ static const vshCmdOptDef opts_setmem[] = {
.flags = VSH_OFLAG_REQ,
.help = N_("new memory size, as scaled integer (default KiB)")
},
+ {.name = "virtio",
+ .type = VSH_OT_BOOL,
+ .help = N_("modify virtio memory instead of top level domain memory")
+ },
+ {.name = "node",
+ .type = VSH_OT_INT,
+ .help = N_("guest numa node"),
+ },
+ {.name = "alias",
+ .type = VSH_OT_STRING,
+ .help = N_("memory device alias"),
+ },
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
VIRSH_COMMON_OPT_DOMAIN_LIVE,
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
{.name = NULL}
};
+
+static int
+virshDomainSetmemVirtio(vshControl *ctl,
+ virDomainPtr dom,
+ unsigned long kibibytes,
+ int numaNode,
+ const char *alias,
+ unsigned int flags)
+{
+ g_autoptr(xmlDoc) doc = NULL;
+ g_autoptr(xmlXPathContext) ctxt = NULL;
+ g_autofree char *xpath = NULL;
+ int nmems;
+ g_autofree xmlNodePtr *mems = NULL;
+ xmlNodePtr requestedSizeNode = NULL;
+ g_autofree char *kibibytesStr = NULL;
+ g_autoptr(xmlBuffer) xmlbuf = NULL;
+ unsigned int domainXMLFlags = 0;
+ const char *updatedMemoryXML = NULL;
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG)
+ domainXMLFlags |= VIR_DOMAIN_XML_INACTIVE;
+
+ if (virshDomainGetXMLFromDom(ctl, dom, domainXMLFlags, &doc, &ctxt) < 0)
+ return -1;
+
+ if (alias) {
+ xpath =
g_strdup_printf("/domain/devices/memory[./alias/@name='%s']", alias);
+ } else if (numaNode >= 0) {
+ xpath =
g_strdup_printf("/domain/devices/memory[./target/node/text()=%d]", numaNode);
+ } else {
+ xpath = g_strdup("/domain/devices/memory[@model='virtio' and
not(./source/pmem)]");
+ }
+
+ nmems = virXPathNodeSet(xpath, ctxt, &mems);
+ if (nmems < 0) {
+ vshSaveLibvirtError();
+ return -1;
+ } else if (nmems == 0) {
+ vshError(ctl, _("no virtio-mem device found"));
+ return -1;
+ } else if (nmems > 1) {
+ vshError(ctl, _("multiple virtio-mem devices found"));
+ return -1;
+ }
+
+ ctxt->node = mems[0];
+
+ 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 (!(xmlbuf = xmlBufferCreate())) {
+ vshError(ctl, _("unable to allocate XML buffer"));
+ return -1;
+ }
+
+ if (xmlNodeDump(xmlbuf, doc, mems[0], 0, 1) < 0) {
+ vshError(ctl, _("unable to format new <memory/> node"));
+ return -1;
+ }
+
+ updatedMemoryXML = (const char *)xmlBufferContent(xmlbuf);
+
+ if (virDomainUpdateDeviceFlags(dom, updatedMemoryXML, flags) < 0)
+ return -1;
+
+ return 0;
+}
+
+
static bool
cmdSetmem(vshControl *ctl, const vshCmd *cmd)
{
@@ -9005,7 +9094,7 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
unsigned long long bytes = 0;
unsigned long long max;
unsigned long kibibytes = 0;
- bool ret = true;
+ bool ret = false;
bool config = vshCommandOptBool(cmd, "config");
bool live = vshCommandOptBool(cmd, "live");
bool current = vshCommandOptBool(cmd, "current");
@@ -9013,6 +9102,7 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+ VSH_EXCLUSIVE_OPTIONS("node", "alias");
if (config)
flags |= VIR_DOMAIN_AFFECT_CONFIG;
@@ -9028,20 +9118,36 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
max = 1024ull * ULONG_MAX;
else
max = ULONG_MAX;
- if (vshCommandOptScaledInt(ctl, cmd, "size", &bytes, 1024, max) < 0)
{
- virshDomainFree(dom);
- return false;
- }
+ if (vshCommandOptScaledInt(ctl, cmd, "size", &bytes, 1024, max) <
0)
+ goto cleanup;
+
kibibytes = VIR_DIV_UP(bytes, 1024);
- if (flags == 0) {
- if (virDomainSetMemory(dom, kibibytes) != 0)
- ret = false;
+ if (vshCommandOptBool(cmd, "virtio")) {
+ int numaNode = -1;
+ const char *alias = NULL;
+
+ if (vshCommandOptInt(ctl, cmd, "node", &numaNode) < 0)
+ goto cleanup;
+
+ if (vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0)
+ goto cleanup;
+
+ if (virshDomainSetmemVirtio(ctl, dom, kibibytes,
+ numaNode, alias, flags) < 0)
+ goto cleanup;
} else {
- if (virDomainSetMemoryFlags(dom, kibibytes, flags) < 0)
- ret = false;
+ if (flags == 0) {
+ if (virDomainSetMemory(dom, kibibytes) != 0)
+ goto cleanup;
+ } else {
+ if (virDomainSetMemoryFlags(dom, kibibytes, flags) < 0)
+ goto cleanup;
+ }
}
+ ret = true;
+ cleanup:
virshDomainFree(dom);
return ret;
}
--
2.26.2