Add a few helpers that allow to operate with memory device definitions
on the domain config and use them to implement memory device coldplug in
the qemu driver.
---
src/conf/domain_conf.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 10 +++++
src/libvirt_private.syms | 4 ++
src/qemu/qemu_driver.c | 15 ++++++-
4 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6b9c15e..3c33f5a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -12416,6 +12416,107 @@ virDomainChrRemove(virDomainDefPtr vmdef,
return ret;
}
+
+static int
+virDomainMemoryFindByDefInternal(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem,
+ bool allowAddressFallback)
+{
+ size_t i;
+
+ for (i = 0; i < def->nmems; i++) {
+ virDomainMemoryDefPtr tmp = def->mems[i];
+
+ /* address, if present */
+ if (allowAddressFallback) {
+ if (tmp->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+ continue;
+ } else {
+ if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ !virDomainDeviceInfoAddressIsEqual(&tmp->info,
&mem->info))
+ continue;
+ }
+
+ /* alias, if present */
+ if (mem->info.alias &&
+ STRNEQ_NULLABLE(tmp->info.alias, mem->info.alias))
+ continue;
+
+ /* target info -> always present */
+ if (tmp->model != mem->model ||
+ tmp->targetNode != mem->targetNode ||
+ tmp->size != mem->size)
+ continue;
+
+ /* source stuff -> match with device */
+ if (tmp->pagesize != mem->pagesize)
+ continue;
+
+ if (!virBitmapEqual(tmp->sourceNodes, mem->sourceNodes))
+ continue;
+
+ break;
+ }
+
+ if (i == def->nmems)
+ return -1;
+
+ return i;
+}
+
+
+int
+virDomainMemoryFindByDef(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem)
+{
+ return virDomainMemoryFindByDefInternal(def, mem, false);
+}
+
+
+int
+virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem)
+{
+ int ret;
+
+ if ((ret = virDomainMemoryFindByDefInternal(def, mem, false)) < 0)
+ ret = virDomainMemoryFindByDefInternal(def, mem, true);
+
+ return ret;
+}
+
+
+int
+virDomainMemoryInsert(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem)
+{
+ int id = def->nmems;
+
+ if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ virDomainDeviceInfoHasAddress(def, &mem->info)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Domain already contains a device with the same "
+ "address"));
+ return -1;
+ }
+
+ if (VIR_APPEND_ELEMENT(def->mems, def->nmems, mem) < 0)
+ return -1;
+
+ return id;
+}
+
+
+virDomainMemoryDefPtr
+virDomainMemoryRemove(virDomainDefPtr def,
+ int idx)
+{
+ virDomainMemoryDefPtr ret = def->mems[idx];
+ VIR_DELETE_ELEMENT(def->mems, idx, def->nmems);
+ return ret;
+}
+
+
char *
virDomainDefGetDefaultEmulator(virDomainDefPtr def,
virCapsPtr caps)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 0d2b8d8..924fa4e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2824,6 +2824,16 @@ virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const
char *model);
typedef const char* (*virEventActionToStringFunc)(int type);
typedef int (*virEventActionFromStringFunc)(const char *type);
+int virDomainMemoryInsert(virDomainDefPtr def, virDomainMemoryDefPtr mem)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+virDomainMemoryDefPtr virDomainMemoryRemove(virDomainDefPtr def, int idx)
+ ATTRIBUTE_NONNULL(1);
+int virDomainMemoryFindByDef(virDomainDefPtr def, virDomainMemoryDefPtr mem)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
VIR_ENUM_DECL(virDomainTaint)
VIR_ENUM_DECL(virDomainVirt)
VIR_ENUM_DECL(virDomainBoot)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a3d1815..9723878 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -327,6 +327,10 @@ virDomainLockFailureTypeToString;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainMemoryDefFree;
+virDomainMemoryFindByDef;
+virDomainMemoryFindInactiveByDef;
+virDomainMemoryInsert;
+virDomainMemoryRemove;
virDomainNetAppendIpAddress;
virDomainNetDefFormat;
virDomainNetDefFree;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index df23aaa..48b852a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7345,7 +7345,10 @@ qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps,
break;
case VIR_DOMAIN_DEVICE_MEMORY:
- /* TODO: implement later */
+ if (virDomainMemoryInsert(vmdef, dev->data.memory) < 0)
+ return -1;
+ dev->data.memory = NULL;
+ break;
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
@@ -7464,7 +7467,15 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
break;
case VIR_DOMAIN_DEVICE_MEMORY:
- /* TODO: implement later */
+ if ((idx = virDomainMemoryFindInactiveByDef(vmdef,
+ dev->data.memory)) < 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("matching memory device was not found"));
+ return -1;
+ }
+
+ virDomainMemoryDefFree(virDomainMemoryRemove(vmdef, idx));
+ break;
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
--
2.2.2