There are three APIs that allow changing IOThreads: virDomainAddIOThread() virDomainDelIOThread() virDomainSetIOThreadParams() In case of QEMU driver these are handled by qemuDomainChgIOThread() which attempts to be versatile enough to work on both inactive and live domain definitions at the same time. However, it's a bit clumsy - when a change to live definition succeeds but fails in inactive definition then there's no rollback. And somewhat rightfully so - changes to live definition are in general harder to roll back. Therefore, do what we do elsewhere (qemuDomainAttachDeviceLiveAndConfig(), qemuDomainDetachDeviceAliasLiveAndConfig(), ...): 1) do the change to inactive XML first, 2) in fact, do the change to a copy of inactive XML, 3) swap inactive XML and its copy only after everything succeeded. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/qemu/qemu_driver.c | 98 ++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c4418df1ed..e30b1b8d84 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5595,6 +5595,7 @@ qemuDomainChgIOThread(virQEMUDriver *driver, { g_autoptr(virQEMUDriverConfig) cfg = NULL; qemuDomainObjPrivate *priv; + g_autoptr(virDomainDef) defcopy = NULL; virDomainDef *def; virDomainDef *persistentDef; virDomainIOThreadIDDef *iothreaddef = NULL; @@ -5610,6 +5611,55 @@ qemuDomainChgIOThread(virQEMUDriver *driver, if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) goto endjob; + if (persistentDef) { + /* Make a copy of persistent definition and do all the changes there. + * Swap the definitions only after changes to live definition + * succeeded. */ + if (!(defcopy = virDomainObjCopyPersistentDef(vm, driver->xmlopt, + priv->qemuCaps))) + return -1; + + switch (action) { + case VIR_DOMAIN_IOTHREAD_ACTION_ADD: + if (virDomainDriverAddIOThreadCheck(defcopy, iothread.iothread_id) < 0) + goto endjob; + + if (!virDomainIOThreadIDAdd(defcopy, iothread.iothread_id)) + goto endjob; + + break; + + case VIR_DOMAIN_IOTHREAD_ACTION_DEL: + if (virDomainDriverDelIOThreadCheck(defcopy, iothread.iothread_id) < 0) + goto endjob; + + virDomainIOThreadIDDel(defcopy, iothread.iothread_id); + + break; + + case VIR_DOMAIN_IOTHREAD_ACTION_MOD: + iothreaddef = virDomainIOThreadIDFind(defcopy, iothread.iothread_id); + + if (!iothreaddef) { + virReportError(VIR_ERR_INVALID_ARG, + _("cannot find IOThread '%u' in iothreadids"), + iothread.iothread_id); + goto endjob; + } + + if (qemuDomainIOThreadValidate(iothreaddef, iothread, false) < 0) + goto endjob; + + if (qemuDomainHotplugModIOThreadIDDef(iothreaddef, iothread) < 0) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("configuring persistent polling values is not supported")); + goto endjob; + } + + break; + } + } + if (def) { if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_IOTHREAD)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -5660,50 +5710,12 @@ qemuDomainChgIOThread(virQEMUDriver *driver, qemuDomainSaveStatus(vm); } - if (persistentDef) { - switch (action) { - case VIR_DOMAIN_IOTHREAD_ACTION_ADD: - if (virDomainDriverAddIOThreadCheck(persistentDef, iothread.iothread_id) < 0) - goto endjob; - - if (!virDomainIOThreadIDAdd(persistentDef, iothread.iothread_id)) - goto endjob; - - break; - - case VIR_DOMAIN_IOTHREAD_ACTION_DEL: - if (virDomainDriverDelIOThreadCheck(persistentDef, iothread.iothread_id) < 0) - goto endjob; - - virDomainIOThreadIDDel(persistentDef, iothread.iothread_id); - - break; - - case VIR_DOMAIN_IOTHREAD_ACTION_MOD: - iothreaddef = virDomainIOThreadIDFind(persistentDef, iothread.iothread_id); - - if (!iothreaddef) { - virReportError(VIR_ERR_INVALID_ARG, - _("cannot find IOThread '%u' in iothreadids"), - iothread.iothread_id); - goto endjob; - } - - if (qemuDomainIOThreadValidate(iothreaddef, iothread, false) < 0) - goto endjob; - - if (qemuDomainHotplugModIOThreadIDDef(iothreaddef, iothread) < 0) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("configuring persistent polling values is not supported")); - goto endjob; - } - - break; - } - - if (virDomainDefSave(persistentDef, driver->xmlopt, - cfg->configDir) < 0) + /* Finally, if no error until here, we can save config. */ + if (defcopy) { + if (virDomainDefSave(defcopy, driver->xmlopt, cfg->configDir) < 0) goto endjob; + + virDomainObjAssignDef(vm, &defcopy, false, NULL); } ret = 0; -- 2.35.1