As advertised in the previous commit, we want' to be able to
change 'requested-size' attribute of virtio-mem on the fly. This
commit does exactly that. Changing anything else is checked for
and forbidden.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/conf/domain_conf.c | 23 +++++
src/conf/domain_conf.h | 3 +
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 165 ++++++++++++++++++++++++++++++++++-
src/qemu/qemu_hotplug.c | 18 ++++
src/qemu/qemu_hotplug.h | 5 ++
src/qemu/qemu_monitor.c | 13 +++
src/qemu/qemu_monitor.h | 4 +
src/qemu/qemu_monitor_json.c | 15 ++++
src/qemu/qemu_monitor_json.h | 5 ++
10 files changed, 251 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0a402f1a51..5db1fee16b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18781,6 +18781,29 @@ virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
}
+ssize_t
+virDomainMemoryFindByDeviceInfo(virDomainDefPtr def,
+ virDomainDeviceInfoPtr info)
+{
+ size_t i;
+
+ for (i = 0; i < def->nmems; i++) {
+ virDomainMemoryDefPtr tmp = def->mems[i];
+
+ if (!virDomainDeviceInfoAddressIsEqual(&tmp->info, info))
+ continue;
+
+ /* alias, if present */
+ if (STRNEQ_NULLABLE(tmp->info.alias, info->alias))
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+
/**
* virDomainMemoryInsert:
*
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3f111e994b..31892c4941 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3580,6 +3580,9 @@ int virDomainMemoryFindByDef(virDomainDefPtr def,
virDomainMemoryDefPtr mem)
int virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
virDomainMemoryDefPtr mem)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
+ssize_t virDomainMemoryFindByDeviceInfo(virDomainDefPtr dev,
+ virDomainDeviceInfoPtr info)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
int virDomainShmemDefInsert(virDomainDefPtr def, virDomainShmemDefPtr shmem)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f581676227..1bed019aac 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -497,6 +497,7 @@ virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainMemoryDefFree;
virDomainMemoryFindByDef;
+virDomainMemoryFindByDeviceInfo;
virDomainMemoryFindInactiveByDef;
virDomainMemoryInsert;
virDomainMemoryModelTypeToString;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 391596ba11..677f921920 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7109,6 +7109,158 @@ qemuDomainChangeDiskLive(virDomainObjPtr vm,
return 0;
}
+
+static bool
+qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef,
+ const virDomainMemoryDef *newDef)
+{
+ /* The only thing that is allowed to change is 'requestedsize' for virtio
+ * model. */
+ if (oldDef->model != newDef->model) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory model from '%s' to
'%s'"),
+ virDomainMemoryModelTypeToString(oldDef->model),
+ virDomainMemoryModelTypeToString(newDef->model));
+ return false;
+ }
+
+ if (oldDef->access != newDef->access) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory access from '%s' to
'%s'"),
+ virDomainMemoryAccessTypeToString(oldDef->access),
+ virDomainMemoryAccessTypeToString(newDef->access));
+ return false;
+ }
+
+ if (oldDef->discard != newDef->discard) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory discard from '%s' to
'%s'"),
+ virTristateBoolTypeToString(oldDef->discard),
+ virTristateBoolTypeToString(newDef->discard));
+ return false;
+ }
+
+ if (oldDef->targetNode != newDef->targetNode) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory targetNode from '%d' to
'%d'"),
+ oldDef->targetNode, newDef->targetNode);
+ return false;
+ }
+
+ if (oldDef->size != newDef->size) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory size from '%llu' to
'%llu'"),
+ oldDef->size, newDef->size);
+ return false;
+ }
+
+ if (oldDef->blocksize != newDef->blocksize) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory block size from '%llu' to
'%llu'"),
+ oldDef->blocksize, newDef->blocksize);
+ return false;
+ }
+
+ /* requestedsize can change */
+
+ if (oldDef->readonly != newDef->readonly) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot modify memory pmem flag"));
+ return false;
+ }
+
+ if (virUUIDIsValid(oldDef->uuid) &&
+ memcmp(oldDef->uuid, newDef, VIR_UUID_BUFLEN) != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot modify memory UUID"));
+ return false;
+ }
+
+ switch (oldDef->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_VIRTIO:
+ if (STRNEQ_NULLABLE(oldDef->s.virtio.path, newDef->s.virtio.path)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory path from '%s' to
'%s'"),
+ NULLSTR(oldDef->s.virtio.path),
+ NULLSTR(newDef->s.virtio.path));
+ return false;
+ }
+
+ if (oldDef->s.virtio.pmem != newDef->s.virtio.pmem) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot modify memory pmem flag"));
+ return false;
+ }
+
+ if (!virBitmapEqual(oldDef->s.virtio.sourceNodes,
+ newDef->s.virtio.sourceNodes)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot modify memory source nodes"));
+ return false;
+ }
+
+ if (oldDef->s.virtio.pagesize != newDef->s.virtio.pagesize) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory pagesize from '%llu' to
'%llu'"),
+ oldDef->s.virtio.pagesize,
+ newDef->s.virtio.pagesize);
+ return false;
+ }
+ break;
+
+ case VIR_DOMAIN_MEMORY_MODEL_NONE:
+ case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_LAST:
+ case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory of model '%s'"),
+ virDomainMemoryModelTypeToString(oldDef->model));
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+
+static int
+qemuDomainChangeMemoryLive(virQEMUDriverPtr driver G_GNUC_UNUSED,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev)
+{
+ virDomainMemoryDefPtr newDef = dev->data.memory;
+ virDomainMemoryDefPtr oldDef = NULL;
+ ssize_t idx;
+
+ idx = virDomainMemoryFindByDeviceInfo(vm->def,
&dev->data.memory->info);
+ if (idx < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("memory '%s' not found"),
dev->data.memory->info.alias);
+ return -1;
+ }
+
+ oldDef = vm->def->mems[idx];
+
+ if (newDef->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO ||
+ newDef->s.virtio.pmem) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("changing anything but <requested/> size for
virtio-mem is not implemented yet"));
+ return -1;
+ }
+
+ if (!qemuDomainChangeMemoryLiveValidateChange(oldDef, newDef))
+ return -1;
+
+ if (qemuDomainChangeMemoryRequestedSize(driver, vm,
+ newDef->info.alias,
+ newDef->requestedsize) < 0)
+ return -1;
+
+ oldDef->requestedsize = newDef->requestedsize;
+ return 0;
+}
+
+
static int
qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
virDomainDeviceDefPtr dev,
@@ -7150,6 +7302,18 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
ret = qemuDomainChangeNet(driver, vm, dev);
break;
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ if ((idx = virDomainMemoryFindByDeviceInfo(vm->def,
&dev->data.memory->info)) >= 0) {
+ oldDev.data.memory = vm->def->mems[idx];
+ if (virDomainDefCompatibleDevice(vm->def, dev, &oldDev,
+ VIR_DOMAIN_DEVICE_ACTION_UPDATE,
+ true) < 0)
+ return -1;
+ }
+
+ ret = qemuDomainChangeMemoryLive(driver, vm, dev);
+ break;
+
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
@@ -7165,7 +7329,6 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_HOSTDEV:
case VIR_DOMAIN_DEVICE_CONTROLLER:
case VIR_DOMAIN_DEVICE_REDIRDEV:
- case VIR_DOMAIN_DEVICE_MEMORY:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index bc5dc02a2f..a18fa6d362 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -6672,3 +6672,21 @@ qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
virBitmapFree(livevcpus);
return ret;
}
+
+
+int
+qemuDomainChangeMemoryRequestedSize(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *alias,
+ unsigned long long requestedsize)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int rc;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+ rc = qemuMonitorChangeMemoryRequestedSize(priv->mon, alias, requestedsize);
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ return -1;
+
+ return rc;
+}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 6287c5b5e8..9e551a1f82 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -160,3 +160,8 @@ int qemuHotplugAttachDBusVMState(virQEMUDriverPtr driver,
int qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver,
virDomainObjPtr vm,
qemuDomainAsyncJob asyncJob);
+
+int qemuDomainChangeMemoryRequestedSize(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *alias,
+ unsigned long long requestedsize);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f2ed165b22..ace7c889d4 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4769,3 +4769,16 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
bitmap, syncmode);
}
+
+
+int
+qemuMonitorChangeMemoryRequestedSize(qemuMonitorPtr mon,
+ const char *alias,
+ unsigned long long requestedsize)
+{
+ VIR_DEBUG("alias=%s requestedsize=%llu", alias, requestedsize);
+
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONChangeMemoryRequestedSize(mon, alias, requestedsize);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index d301568e40..c792c95c46 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1527,3 +1527,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
const char *target,
const char *bitmap,
qemuMonitorTransactionBackupSyncMode syncmode);
+
+int qemuMonitorChangeMemoryRequestedSize(qemuMonitorPtr mon,
+ const char *alias,
+ unsigned long long requestedsize);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 723bdb4426..3d94181afb 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9635,3 +9635,18 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
migratable);
}
+
+
+int
+qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitorPtr mon,
+ const char *alias,
+ unsigned long long requestedsize)
+{
+ g_autofree char *path = g_strdup_printf("/machine/peripheral/%s", alias);
+ qemuMonitorJSONObjectProperty prop = {
+ .type = QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
+ .val.ul = requestedsize * 1024, /* monitor needs bytes */
+ };
+
+ return qemuMonitorJSONSetObjectProperty(mon, path, "requested-size",
&prop);
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index b588722d90..dcf101a165 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -710,3 +710,8 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
int
qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
bool *migratable);
+
+int
+qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitorPtr mon,
+ const char *alias,
+ unsigned long long requestedsize);
--
2.26.2