}
+/**
+ * virDomainMemoryFindByDeviceInfo:
+ * @def: domain defintion
+ * @info: device info to match
+ * @pos: store position within array
+ *
+ * For given domain definition @def find <memory/> device with
+ * matching address and matching device alias (if set in @info,
+ * otherwise ignored).
+ *
+ * If @pos is not NULL then the position of the matched device
+ * within the array is stored there.
+ *
+ * Returns: device if found,
+ * NULL otherwise.
+ */
+virDomainMemoryDef *
+virDomainMemoryFindByDeviceInfo(virDomainDef *def,
+ virDomainDeviceInfo *info,
+ int *pos)
+{
+ size_t i;
+
+ for (i = 0; i < def->nmems; i++) {
+ virDomainMemoryDef *tmp = def->mems[i];
+
+ if (!virDomainDeviceInfoAddressIsEqual(&tmp->info, info))
+ continue;
+
+ /* alias, if present */
+ if (info->alias &&
+ STRNEQ_NULLABLE(tmp->info.alias, info->alias))
+ continue;
+
+ if (pos)
+ *pos = i;
+
+ return tmp;
+ }
+
+ return NULL;
+}
+
+
/**
* virDomainMemoryInsert:
*
return -1;
}
- if ((virDomainDefGetMemoryTotal(def) + sz) > def->mem.max_memory) {
+ if (action == VIR_DOMAIN_DEVICE_ACTION_ATTACH &&
+ (virDomainDefGetMemoryTotal(def) + sz) > def->mem.max_memory) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Attaching memory device with size '%llu' would "
"exceed domain's maxMemory config size '%llu'"),
return 0;
}
+
+static bool
+qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef,
+ const virDomainMemoryDef *newDef)
+{
+ /* The only thing that is allowed to change is 'requestedsize' for
+ * virtio-mem model. Check if user isn't trying to sneak in change for
+ * something else. */
+
+ switch (oldDef->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+ break;
+
+ case VIR_DOMAIN_MEMORY_MODEL_NONE:
+ case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+ case VIR_DOMAIN_MEMORY_MODEL_LAST:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory of model '%s'"),
+ virDomainMemoryModelTypeToString(oldDef->model));
+ return false;
+ break;
+ }
+
+ 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 (!virBitmapEqual(oldDef->sourceNodes,
+ newDef->sourceNodes)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot modify memory source nodes"));
+ return false;
+ }
+
+ if (oldDef->pagesize != newDef->pagesize) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory pagesize from '%llu' to '%llu'"),
+ oldDef->pagesize,
+ newDef->pagesize);
+ return false;
+ }
+
+ if (STRNEQ_NULLABLE(oldDef->nvdimmPath, newDef->nvdimmPath)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory path from '%s' to '%s'"),
+ NULLSTR(oldDef->nvdimmPath),
+ NULLSTR(newDef->nvdimmPath));
+ return false;
+ }
+
+ if (oldDef->alignsize != newDef->alignsize) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory align size from '%llu' to '%llu'"),
+ oldDef->alignsize, newDef->alignsize);
+ return false;
+ }
+
+ if (oldDef->nvdimmPmem != newDef->nvdimmPmem) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory pmem from '%d' to '%d'"),
+ oldDef->nvdimmPmem, newDef->nvdimmPmem);
+ 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->labelsize != newDef->labelsize) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot modify memory label size from '%llu' to '%llu'"),
+ oldDef->labelsize, newDef->labelsize);
+ 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 ((oldDef->uuid || newDef->uuid) &&
+ !(oldDef->uuid && newDef->uuid &&
+ memcmp(oldDef->uuid, newDef->uuid, VIR_UUID_BUFLEN) == 0)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot modify memory UUID"));
+ return false;
+ }
+
+ return true;
+}
+
+
+static int
+qemuDomainChangeMemoryLive(virQEMUDriver *driver G_GNUC_UNUSED,
+ virDomainObj *vm,
+ virDomainDeviceDef *dev)
+{
+ virDomainDeviceDef oldDev = { .type = VIR_DOMAIN_DEVICE_MEMORY };
+ virDomainMemoryDef *newDef = dev->data.memory;
+ virDomainMemoryDef *oldDef = NULL;
+
+ oldDef = virDomainMemoryFindByDeviceInfo(vm->def, &dev->data.memory->info, NULL);
+ if (!oldDef) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("memory '%s' not found"), dev->data.memory->info.alias);
+ return -1;
+ }
+
+ oldDev.data.memory = oldDef;
+
+ if (virDomainDefCompatibleDevice(vm->def, dev, &oldDev,
+ VIR_DOMAIN_DEVICE_ACTION_UPDATE,
+ true) < 0)
+ 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(virDomainObj *vm,
virDomainDeviceDef *dev,
ret = qemuDomainChangeNet(driver, vm, dev);
break;
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ ret = qemuDomainChangeMemoryLive(driver, vm, dev);
+ break;
+
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
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: