[PATCH v2 22/27] qemu: Wire up <memory/> live update

Michal Privoznik mprivozn at redhat.com
Thu Dec 3 12:36:25 UTC 2020


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 at 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 0551f6f266..a4293f1749 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18762,6 +18762,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 f16dc0a029..d0814d7639 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3584,6 +3584,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 2f640ef1c4..7014d602b6 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 bca1c84630..edc109cb28 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7104,6 +7104,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,
@@ -7145,6 +7297,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:
@@ -7160,7 +7324,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 ce1a06c4c8..0e2cc0b76c 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4733,3 +4733,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 8bc092870b..3005adc1e0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1518,3 +1518,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 e82d762925..4046d0b3b0 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9467,3 +9467,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 d2928b0ffc..d4b80b5f27 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -704,3 +704,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




More information about the libvir-list mailing list