[PATCH v5 0/8] Implement detach device related APIs for test driver

diff to v4: - Rebase to current master diff to v3: - Add virDomainDeviceDefOperationsCallbacks to xmlopt for de-duplicating purpose - Add virDomainDeviceTypeFlags for de-duplicating purpose - Remove the memballoon helper function - Squash test_driver commits - Move test device xmls to generichotplugdata - Reimplement tests with internal APIs link to v4: https://listman.redhat.com/archives/libvir-list/2021-December/msg00108.html link to v3: https://listman.redhat.com/archives/libvir-list/2021-November/msg00288.html link to CI: https://gitlab.com/lukedyue/libvirt/-/pipelines/464756840 Luke Yue (8): conf: Introduce virDomainInputDefRemove and fix memory leak conf: Introduce virDomainDeviceDefOperationsCallbacks to xmlopt conf: Add virDomainDeviceTypeFlags and use it in various drivers conf: Add tpm helpers for future use domain_driver: extract DetachXXXDeviceConfig related functions and use them test_driver: Implement virDomainDetachDeviceFlags examples: xml: test: add xml for testing devices related APIs tests: Add generichotplugtest examples/xml/test/meson.build | 1 + examples/xml/test/testdomfc5.xml | 54 ++ examples/xml/test/testnodeinline.xml | 54 ++ src/bhyve/bhyve_domain.c | 2 +- src/ch/ch_conf.c | 2 +- src/conf/domain_conf.c | 572 +++++++++++++++++- src/conf/domain_conf.h | 135 ++++- src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 3 +- src/libvirt_private.syms | 21 + src/libxl/libxl_conf.c | 3 +- src/libxl/libxl_domain.c | 8 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 73 +-- src/lxc/lxc_conf.c | 3 +- src/lxc/lxc_domain.c | 7 + src/lxc/lxc_domain.h | 1 + src/lxc/lxc_driver.c | 62 +- src/openvz/openvz_conf.c | 2 +- src/qemu/qemu_conf.c | 3 +- src/qemu/qemu_domain.c | 39 ++ src/qemu/qemu_domain.h | 6 + src/qemu/qemu_driver.c | 206 +------ src/qemu/qemu_process.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/test/test_driver.c | 197 +++++- src/vbox/vbox_common.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/vz/vz_driver.c | 2 +- tests/bhyveargv2xmltest.c | 2 +- .../generichotplug-controller.xml | 1 + .../generichotplug-disk-cdrom.xml | 5 + .../generichotplug-filesystem.xml | 6 + .../generichotplug-hostdev.xml | 5 + .../generichotplug-input.xml | 1 + .../generichotplug-interface.xml | 6 + .../generichotplug-lease.xml | 5 + .../generichotplug-memballoon.xml | 3 + .../generichotplug-memory.xml | 6 + .../generichotplugdata/generichotplug-rng.xml | 4 + .../generichotplug-shmem.xml | 4 + .../generichotplug-sound.xml | 3 + .../generichotplugdata/generichotplug-tpm.xml | 5 + .../generichotplug-vsock.xml | 3 + .../generichotplug-watchdog.xml | 1 + tests/generichotplugtest.c | 178 ++++++ tests/meson.build | 1 + tests/testutils.c | 2 +- 49 files changed, 1378 insertions(+), 332 deletions(-) create mode 100644 tests/generichotplugdata/generichotplug-controller.xml create mode 100644 tests/generichotplugdata/generichotplug-disk-cdrom.xml create mode 100644 tests/generichotplugdata/generichotplug-filesystem.xml create mode 100644 tests/generichotplugdata/generichotplug-hostdev.xml create mode 100644 tests/generichotplugdata/generichotplug-input.xml create mode 100644 tests/generichotplugdata/generichotplug-interface.xml create mode 100644 tests/generichotplugdata/generichotplug-lease.xml create mode 100644 tests/generichotplugdata/generichotplug-memballoon.xml create mode 100644 tests/generichotplugdata/generichotplug-memory.xml create mode 100644 tests/generichotplugdata/generichotplug-rng.xml create mode 100644 tests/generichotplugdata/generichotplug-shmem.xml create mode 100644 tests/generichotplugdata/generichotplug-sound.xml create mode 100644 tests/generichotplugdata/generichotplug-tpm.xml create mode 100644 tests/generichotplugdata/generichotplug-vsock.xml create mode 100644 tests/generichotplugdata/generichotplug-watchdog.xml create mode 100644 tests/generichotplugtest.c -- 2.35.1

Signed-off-by: Luke Yue <lukedyue@gmail.com> --- src/conf/domain_conf.c | 12 ++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 3 ++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d66496c9b7..c8c2f13f8b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16734,6 +16734,18 @@ virDomainInputDefFind(const virDomainDef *def, } +virDomainInputDef * +virDomainInputDefRemove(virDomainDef *def, + size_t idx) +{ + virDomainInputDef *ret = def->inputs[idx]; + + VIR_DELETE_ELEMENT(def->inputs, idx, def->ninputs); + + return ret; +} + + bool virDomainVsockDefEquals(const virDomainVsockDef *a, const virDomainVsockDef *b) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index b2922e8cff..c0167eee85 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3888,6 +3888,8 @@ virDomainShmemDef *virDomainShmemDefRemove(virDomainDef *def, size_t idx) ssize_t virDomainInputDefFind(const virDomainDef *def, const virDomainInputDef *input) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; +virDomainInputDef *virDomainInputDefRemove(virDomainDef *def, size_t idx) + ATTRIBUTE_NONNULL(1); bool virDomainVsockDefEquals(const virDomainVsockDef *a, const virDomainVsockDef *b) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 398cc79ee3..abdc8eaef7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -480,6 +480,7 @@ virDomainInputBusTypeToString; virDomainInputDefFind; virDomainInputDefFree; virDomainInputDefGetPath; +virDomainInputDefRemove; virDomainInputSourceGrabToggleTypeFromString; virDomainInputSourceGrabToggleTypeToString; virDomainInputSourceGrabTypeFromString; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 698f57f00e..864ea10685 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7502,7 +7502,8 @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef, _("matching input device not found")); return -1; } - VIR_DELETE_ELEMENT(vmdef->inputs, idx, vmdef->ninputs); + + virDomainInputDefFree(virDomainInputDefRemove(vmdef, idx)); break; case VIR_DOMAIN_DEVICE_VSOCK: -- 2.35.1

virDomainDeviceDefOperationsCallbacks would enable virDomainXMLOption to gain driver specific callback for attaching / detaching / updating devices, also it can store flags for attachable / detachable / updatable devices that driver supported (currently only add flags for detachable devices). This would be useful when de-duplicate related functions. Signed-off-by: Luke Yue <lukedyue@gmail.com> --- I am not pretty sure whether these functions could be put into virDomainXMLPrivateDataCallbacks or not, so I just create a new one to store them. --- src/bhyve/bhyve_domain.c | 2 +- src/ch/ch_conf.c | 2 +- src/conf/domain_conf.c | 6 +++++- src/conf/domain_conf.h | 18 +++++++++++++++++- src/conf/virconftypes.h | 2 ++ src/hyperv/hyperv_driver.c | 3 ++- src/libxl/libxl_conf.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/qemu/qemu_conf.c | 3 ++- src/qemu/qemu_process.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/test/test_driver.c | 3 ++- src/vbox/vbox_common.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/vz/vz_driver.c | 2 +- tests/bhyveargv2xmltest.c | 2 +- tests/testutils.c | 2 +- 19 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index b526235a4e..1b7986ffff 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -217,7 +217,7 @@ virBhyveDriverCreateXMLConf(struct _bhyveConn *driver) return virDomainXMLOptionNew(&virBhyveDriverDomainDefParserConfig, &virBhyveDriverPrivateDataCallbacks, &virBhyveDriverDomainXMLNamespace, - NULL, NULL); + NULL, NULL, NULL); } diff --git a/src/ch/ch_conf.c b/src/ch/ch_conf.c index 88a23a59cd..fc1313584b 100644 --- a/src/ch/ch_conf.c +++ b/src/ch/ch_conf.c @@ -111,7 +111,7 @@ chDomainXMLConfInit(virCHDriver *driver) virCHDriverDomainDefParserConfig.priv = driver; return virDomainXMLOptionNew(&virCHDriverDomainDefParserConfig, &virCHDriverPrivateDataCallbacks, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } virCHDriverConfig * diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c8c2f13f8b..e19e3deb17 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1579,7 +1579,8 @@ virDomainXMLOptionNew(virDomainDefParserConfig *config, virDomainXMLPrivateDataCallbacks *priv, virXMLNamespace *xmlns, virDomainABIStability *abi, - virSaveCookieCallbacks *saveCookie) + virSaveCookieCallbacks *saveCookie, + virDomainDeviceDefOperationsCallbacks *deviceOps) { virDomainXMLOption *xmlopt; @@ -1604,6 +1605,9 @@ virDomainXMLOptionNew(virDomainDefParserConfig *config, if (saveCookie) xmlopt->saveCookie = *saveCookie; + if (deviceOps) + xmlopt->deviceOps = *deviceOps; + /* Technically this forbids to use one of Xerox's MAC address prefixes in * our hypervisor drivers. This shouldn't ever be a problem. * diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index c0167eee85..14fb9777de 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3208,7 +3208,8 @@ virDomainXMLOption *virDomainXMLOptionNew(virDomainDefParserConfig *config, virDomainXMLPrivateDataCallbacks *priv, virXMLNamespace *xmlns, virDomainABIStability *abi, - virSaveCookieCallbacks *saveCookie); + virSaveCookieCallbacks *saveCookie, + virDomainDeviceDefOperationsCallbacks *deviceOps); virSaveCookieCallbacks * virDomainXMLOptionGetSaveCookie(virDomainXMLOption *xmlopt); @@ -3226,6 +3227,18 @@ virXMLNamespace * virDomainXMLOptionGetNamespace(virDomainXMLOption *xmlopt) ATTRIBUTE_NONNULL(1); +typedef int (*virDomainDeviceDetachFunc)(virDomainDef *vmdef, + virDomainDeviceDef *dev, + unsigned int flags); + +struct _virDomainDeviceDefOperationsCallbacks { + virDomainDeviceDetachFunc detachChr; + virDomainDeviceDetachFunc detachMemballoon; + + /* Flags for detachable devices that driver supported */ + unsigned int detachFlags; +}; + /* This structure holds various callbacks and data needed * while parsing and creating domain XMLs */ struct _virDomainXMLOption { @@ -3248,6 +3261,9 @@ struct _virDomainXMLOption { /* Snapshot postparse callbacks */ virDomainMomentPostParseCallback momentPostParse; + + /* domain specific device operation callbacks */ + virDomainDeviceDefOperationsCallbacks deviceOps; }; G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainXMLOption, virObjectUnref); diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 21420ba8ea..d3bb720c52 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -251,3 +251,5 @@ typedef struct _virDomainXMLOption virDomainXMLOption; typedef struct _virDomainXMLPrivateDataCallbacks virDomainXMLPrivateDataCallbacks; typedef struct _virDomainXenbusControllerOpts virDomainXenbusControllerOpts; + +typedef struct _virDomainDeviceDefOperationsCallbacks virDomainDeviceDefOperationsCallbacks; diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 288c01ad14..732cf4a163 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1766,7 +1766,8 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, goto cleanup; /* init xmlopt for domain XML */ - priv->xmlopt = virDomainXMLOptionNew(&hypervDomainDefParserConfig, NULL, NULL, NULL, NULL); + priv->xmlopt = virDomainXMLOptionNew(&hypervDomainDefParserConfig, + NULL, NULL, NULL, NULL, NULL); if (hypervGetOperatingSystem(priv, &os) < 0) goto cleanup; diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index f062f8e958..032f7196c2 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -2486,5 +2486,5 @@ libxlCreateXMLConf(libxlDriverPrivate *driver) return virDomainXMLOptionNew(&libxlDomainDefParserConfig, &libxlDomainXMLPrivateDataCallbacks, &libxlDriverDomainXMLNamespace, - NULL, NULL); + NULL, NULL, NULL); } diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 8955578d54..01a159438e 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -190,7 +190,7 @@ lxcDomainXMLConfInit(virLXCDriver *driver, const char *defsecmodel) return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig, &virLXCDriverPrivateDataCallbacks, &virLXCDriverDomainXMLNamespace, - NULL, NULL); + NULL, NULL, NULL); } diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 191c79e1e2..5bcb9c584b 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -1063,5 +1063,5 @@ virDomainXMLOption *openvzXMLOption(struct openvz_driver *driver) { openvzDomainDefParserConfig.priv = driver; return virDomainXMLOptionNew(&openvzDomainDefParserConfig, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 81449b8b77..8b2926f766 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1296,7 +1296,8 @@ virQEMUDriverCreateXMLConf(virQEMUDriver *driver, &virQEMUDriverPrivateDataCallbacks, &virQEMUDriverDomainXMLNamespace, &virQEMUDriverDomainABIStability, - &virQEMUDriverDomainSaveCookie); + &virQEMUDriverDomainSaveCookie, + NULL); } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ea586e54c1..42a3062cb9 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9342,7 +9342,7 @@ qemuProcessQMPConnectMonitor(qemuProcessQMP *proc) monConfig.data.nix.path = proc->monpath; monConfig.data.nix.listen = false; - if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || + if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL, NULL)) || !(proc->vm = virDomainObjNew(xmlopt)) || !(proc->vm->def = virDomainDefNew(xmlopt))) return -1; diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 1f1cce8b3d..ead785ee57 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -632,7 +632,7 @@ get_definition(vahControl * ctl, const char *xmlStr) } if (!(ctl->xmlopt = virDomainXMLOptionNew(&virAAHelperDomainDefParserConfig, - NULL, NULL, NULL, NULL))) { + NULL, NULL, NULL, NULL, NULL))) { vah_error(ctl, 0, _("Failed to create XML config object")); return -1; } diff --git a/src/test/test_driver.c b/src/test/test_driver.c index f900123941..e4eb0e87d2 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -462,7 +462,8 @@ testDriverNew(void) if (!(ret = virObjectLockableNew(testDriverClass))) return NULL; - if (!(ret->xmlopt = virDomainXMLOptionNew(&config, &privatecb, &ns, NULL, NULL)) || + if (!(ret->xmlopt = virDomainXMLOptionNew(&config, &privatecb, &ns, + NULL, NULL, NULL)) || !(ret->eventState = virObjectEventStateNew()) || !(ret->ifaces = virInterfaceObjListNew()) || !(ret->domains = virDomainObjListNew()) || diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index eec47a02fc..ce8e7203b1 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -143,7 +143,7 @@ vboxDriverObjNew(void) if (!(driver->caps = vboxCapsInit()) || !(driver->xmlopt = virDomainXMLOptionNew(&vboxDomainDefParserConfig, - NULL, NULL, NULL, NULL))) + NULL, NULL, NULL, NULL, NULL))) goto cleanup; return driver; diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 998ecdb546..4943049df5 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -156,7 +156,7 @@ vmwareDomainXMLConfigInit(struct vmware_driver *driver) .free = vmwareDataFreeFunc }; vmwareDomainDefParserConfig.priv = driver; return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } static virDrvOpenStatus diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index ca65caa9a1..6500ed518e 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -695,7 +695,7 @@ virVMXDomainXMLConfInit(virCaps *caps) { virVMXDomainDefParserConfig.priv = caps; return virDomainXMLOptionNew(&virVMXDomainDefParserConfig, NULL, - &virVMXDomainXMLNamespace, NULL, NULL); + &virVMXDomainXMLNamespace, NULL, NULL, NULL); } char * diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index c16cc2be00..c7224a9cbe 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -330,7 +330,7 @@ vzDriverObjNew(void) if (!(driver->caps = vzBuildCapabilities()) || !(driver->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig, &vzDomainXMLPrivateDataCallbacksPtr, - NULL, NULL, NULL)) || + NULL, NULL, NULL, NULL)) || !(driver->domains = virDomainObjListNew()) || !(driver->domainEventState = virObjectEventStateNew()) || (vzInitVersion(driver) < 0) || diff --git a/tests/bhyveargv2xmltest.c b/tests/bhyveargv2xmltest.c index 2ccc1379b9..92189a2e58 100644 --- a/tests/bhyveargv2xmltest.c +++ b/tests/bhyveargv2xmltest.c @@ -113,7 +113,7 @@ mymain(void) if ((driver.caps = virBhyveCapsBuild()) == NULL) return EXIT_FAILURE; - if ((driver.xmlopt = virDomainXMLOptionNew(NULL, NULL, + if ((driver.xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL, NULL)) == NULL) return EXIT_FAILURE; diff --git a/tests/testutils.c b/tests/testutils.c index 2b37c1965d..949a3cae36 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -988,7 +988,7 @@ static virDomainDefParserConfig virTestGenericDomainDefParserConfig = { virDomainXMLOption *virTestGenericDomainXMLConfInit(void) { return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } -- 2.35.1

Declare and use virDomainDeviceDefOperationsCallbacks in test / QEMU / LXC / libxl drivers to store detachable devices that driver support, this would be useful in future. Also add test driver's memballoon device detach function and QEMU driver's char device detach function to their xmlopt. Signed-off-by: Luke Yue <lukedyue@gmail.com> --- src/conf/domain_conf.h | 31 ++++++++++++++++++++++++++ src/libxl/libxl_conf.c | 3 ++- src/libxl/libxl_domain.c | 8 +++++++ src/libxl/libxl_domain.h | 1 + src/lxc/lxc_conf.c | 3 ++- src/lxc/lxc_domain.c | 7 ++++++ src/lxc/lxc_domain.h | 1 + src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_domain.c | 39 +++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 6 +++++ src/test/test_driver.c | 47 +++++++++++++++++++++++++++++++++++++++- 11 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 14fb9777de..3bb1092b60 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -90,6 +90,37 @@ typedef enum { VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; +typedef enum { + VIR_DOMAIN_DEVICE_FLAG_NONE = (1 << VIR_DOMAIN_DEVICE_NONE), + VIR_DOMAIN_DEVICE_FLAG_DISK = (1 << VIR_DOMAIN_DEVICE_DISK), + VIR_DOMAIN_DEVICE_FLAG_LEASE = (1 << VIR_DOMAIN_DEVICE_LEASE), + VIR_DOMAIN_DEVICE_FLAG_FS = (1 << VIR_DOMAIN_DEVICE_FS), + VIR_DOMAIN_DEVICE_FLAG_NET = (1 << VIR_DOMAIN_DEVICE_NET), + VIR_DOMAIN_DEVICE_FLAG_INPUT = (1 << VIR_DOMAIN_DEVICE_INPUT), + VIR_DOMAIN_DEVICE_FLAG_SOUND = (1 << VIR_DOMAIN_DEVICE_SOUND), + VIR_DOMAIN_DEVICE_FLAG_VIDEO = (1 << VIR_DOMAIN_DEVICE_VIDEO), + VIR_DOMAIN_DEVICE_FLAG_HOSTDEV = (1 << VIR_DOMAIN_DEVICE_HOSTDEV), + VIR_DOMAIN_DEVICE_FLAG_WATCHDOG = (1 << VIR_DOMAIN_DEVICE_WATCHDOG), + VIR_DOMAIN_DEVICE_FLAG_CONTROLLER = (1 << VIR_DOMAIN_DEVICE_CONTROLLER), + VIR_DOMAIN_DEVICE_FLAG_GRAPHICS = (1 << VIR_DOMAIN_DEVICE_GRAPHICS), + VIR_DOMAIN_DEVICE_FLAG_HUB = (1 << VIR_DOMAIN_DEVICE_HUB), + VIR_DOMAIN_DEVICE_FLAG_REDIRDEV = (1 << VIR_DOMAIN_DEVICE_REDIRDEV), + VIR_DOMAIN_DEVICE_FLAG_SMARTCARD = (1 << VIR_DOMAIN_DEVICE_SMARTCARD), + VIR_DOMAIN_DEVICE_FLAG_CHR = (1 << VIR_DOMAIN_DEVICE_CHR), + VIR_DOMAIN_DEVICE_FLAG_MEMBALLOON = (1 << VIR_DOMAIN_DEVICE_MEMBALLOON), + VIR_DOMAIN_DEVICE_FLAG_NVRAM = (1 << VIR_DOMAIN_DEVICE_NVRAM), + VIR_DOMAIN_DEVICE_FLAG_RNG = (1 << VIR_DOMAIN_DEVICE_RNG), + VIR_DOMAIN_DEVICE_FLAG_SHMEM = (1 << VIR_DOMAIN_DEVICE_SHMEM), + VIR_DOMAIN_DEVICE_FLAG_TPM = (1 << VIR_DOMAIN_DEVICE_TPM), + VIR_DOMAIN_DEVICE_FLAG_PANIC = (1 << VIR_DOMAIN_DEVICE_PANIC), + VIR_DOMAIN_DEVICE_FLAG_MEMORY = (1 << VIR_DOMAIN_DEVICE_MEMORY), + VIR_DOMAIN_DEVICE_FLAG_IOMMU = (1 << VIR_DOMAIN_DEVICE_IOMMU), + VIR_DOMAIN_DEVICE_FLAG_VSOCK = (1 << VIR_DOMAIN_DEVICE_VSOCK), + VIR_DOMAIN_DEVICE_FLAG_AUDIO = (1 << VIR_DOMAIN_DEVICE_AUDIO), + + VIR_DOMAIN_DEVICE_FLAG_LAST = (1 << VIR_DOMAIN_DEVICE_LAST) +} virDomainDeviceTypeFlags; + struct _virDomainDeviceDef { int type; /* enum virDomainDeviceType */ union { diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 032f7196c2..aaf4a134a9 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -2486,5 +2486,6 @@ libxlCreateXMLConf(libxlDriverPrivate *driver) return virDomainXMLOptionNew(&libxlDomainDefParserConfig, &libxlDomainXMLPrivateDataCallbacks, &libxlDriverDomainXMLNamespace, - NULL, NULL, NULL); + NULL, NULL, + &libxlDriverDeviceDefOpsCallbacks); } diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 577985b5ea..e20adfd846 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -1599,3 +1599,11 @@ virXMLNamespace libxlDriverDomainXMLNamespace = { .prefix = "xen", .uri = "http://libvirt.org/schemas/domain/xen/1.0", }; + + +virDomainDeviceDefOperationsCallbacks libxlDriverDeviceDefOpsCallbacks = { + .detachFlags = VIR_DOMAIN_DEVICE_FLAG_DISK | + VIR_DOMAIN_DEVICE_FLAG_NET | + VIR_DOMAIN_DEVICE_FLAG_HOSTDEV | + VIR_DOMAIN_DEVICE_FLAG_CONTROLLER, +}; diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 981bfc2bca..1534597cd9 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -68,6 +68,7 @@ struct _libxlDomainObjPrivate { extern virDomainXMLPrivateDataCallbacks libxlDomainXMLPrivateDataCallbacks; extern virDomainDefParserConfig libxlDomainDefParserConfig; extern virXMLNamespace libxlDriverDomainXMLNamespace; +extern virDomainDeviceDefOperationsCallbacks libxlDriverDeviceDefOpsCallbacks; extern const struct libxl_event_hooks ev_hooks; int diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 01a159438e..49b42033d3 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -190,7 +190,8 @@ lxcDomainXMLConfInit(virLXCDriver *driver, const char *defsecmodel) return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig, &virLXCDriverPrivateDataCallbacks, &virLXCDriverDomainXMLNamespace, - NULL, NULL, NULL); + NULL, NULL, + &virLXCDriverDeviceDefOpsCallbacks); } diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 0920e91fd1..5c3bc89c1c 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -496,3 +496,10 @@ virLXCDomainSetRunlevel(virDomainObj *vm, data.st_valid = NULL; return ret; } + + +virDomainDeviceDefOperationsCallbacks virLXCDriverDeviceDefOpsCallbacks = { + .detachFlags = VIR_DOMAIN_DEVICE_FLAG_DISK | + VIR_DOMAIN_DEVICE_FLAG_NET | + VIR_DOMAIN_DEVICE_FLAG_HOSTDEV, +}; diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index 766837bdf1..2bdd67886e 100644 --- a/src/lxc/lxc_domain.h +++ b/src/lxc/lxc_domain.h @@ -92,6 +92,7 @@ struct _virLXCDomainObjPrivate { extern virXMLNamespace virLXCDriverDomainXMLNamespace; extern virDomainXMLPrivateDataCallbacks virLXCDriverPrivateDataCallbacks; extern virDomainDefParserConfig virLXCDriverDomainDefParserConfig; +extern virDomainDeviceDefOperationsCallbacks virLXCDriverDeviceDefOpsCallbacks; int virLXCDomainObjBeginJob(virLXCDriver *driver, diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 8b2926f766..aad361034a 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1297,7 +1297,7 @@ virQEMUDriverCreateXMLConf(virQEMUDriver *driver, &virQEMUDriverDomainXMLNamespace, &virQEMUDriverDomainABIStability, &virQEMUDriverDomainSaveCookie, - NULL); + &virQEMUDriverDeviceDefOpsCallbacks); } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 14b585c6e9..bbf9804f09 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -29,6 +29,7 @@ #include "qemu_process.h" #include "qemu_capabilities.h" #include "qemu_hostdev.h" +#include "qemu_hotplug.h" #include "qemu_migration.h" #include "qemu_migration_params.h" #include "qemu_security.h" @@ -11563,6 +11564,24 @@ qemuDomainDeviceBackendChardevForeachOne(virDomainDeviceDef *dev, return 0; } + +int +qemuDomainDetachDeviceChrConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + unsigned int flags) +{ + virDomainChrDef *chr; + + virCheckFlags(VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (!(chr = qemuDomainChrRemove(vmdef, dev->data.chr))) + return -1; + + virDomainChrDefFree(chr); + + return 0; +} + struct qemuDomainDeviceBackendChardevIterData { qemuDomainDeviceBackendChardevForeachCallback cb; void *cbdata; @@ -11605,3 +11624,23 @@ qemuDomainDeviceBackendChardevForeach(virDomainDef *def, DOMAIN_DEVICE_ITERATE_MISSING_INFO, &data); } + + +virDomainDeviceDefOperationsCallbacks virQEMUDriverDeviceDefOpsCallbacks = { + .detachChr = qemuDomainDetachDeviceChrConfig, + .detachFlags = VIR_DOMAIN_DEVICE_FLAG_DISK | + VIR_DOMAIN_DEVICE_FLAG_NET | + VIR_DOMAIN_DEVICE_FLAG_SOUND | + VIR_DOMAIN_DEVICE_FLAG_HOSTDEV | + VIR_DOMAIN_DEVICE_FLAG_LEASE | + VIR_DOMAIN_DEVICE_FLAG_CONTROLLER | + VIR_DOMAIN_DEVICE_FLAG_CHR | + VIR_DOMAIN_DEVICE_FLAG_FS | + VIR_DOMAIN_DEVICE_FLAG_RNG | + VIR_DOMAIN_DEVICE_FLAG_MEMORY | + VIR_DOMAIN_DEVICE_FLAG_REDIRDEV | + VIR_DOMAIN_DEVICE_FLAG_SHMEM | + VIR_DOMAIN_DEVICE_FLAG_WATCHDOG | + VIR_DOMAIN_DEVICE_FLAG_INPUT | + VIR_DOMAIN_DEVICE_FLAG_VSOCK, +}; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 78474b3f73..79c0fcfe33 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -723,6 +723,7 @@ void qemuDomainObjPrivateDataClear(qemuDomainObjPrivate *priv); extern virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks; extern virXMLNamespace virQEMUDriverDomainXMLNamespace; extern virDomainDefParserConfig virQEMUDriverDomainDefParserConfig; +extern virDomainDeviceDefOperationsCallbacks virQEMUDriverDeviceDefOpsCallbacks; extern virDomainABIStability virQEMUDriverDomainABIStability; extern virSaveCookieCallbacks virQEMUDriverDomainSaveCookie; @@ -1058,3 +1059,8 @@ int qemuDomainDeviceBackendChardevForeach(virDomainDef *def, qemuDomainDeviceBackendChardevForeachCallback cb, void *opaque); + +int +qemuDomainDetachDeviceChrConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + unsigned int flags); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index e4eb0e87d2..2380c37ddb 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -431,6 +431,31 @@ testDomainObjPrivateFree(void *data) } +static int +testDomainDetachMemballoonDevice(virDomainDef *vmdef, + virDomainDeviceDef *dev G_GNUC_UNUSED, + unsigned int flags) +{ + if (flags & VIR_DOMAIN_AFFECT_LIVE) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("detach memballon device on running domain " + "is not supported")); + return -1; + } + + if (!vmdef->memballoon) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no memballoon device was found")); + return -1; + } + + virDomainMemballoonDefFree(vmdef->memballoon); + vmdef->memballoon = NULL; + + return 0; +} + + static testDriver * testDriverNew(void) { @@ -454,6 +479,26 @@ testDriverNew(void) .alloc = testDomainObjPrivateAlloc, .free = testDomainObjPrivateFree, }; + virDomainDeviceDefOperationsCallbacks deviceOps = { + .detachMemballoon = testDomainDetachMemballoonDevice, + .detachFlags = VIR_DOMAIN_DEVICE_FLAG_DISK | + VIR_DOMAIN_DEVICE_FLAG_NET | + VIR_DOMAIN_DEVICE_FLAG_SOUND | + VIR_DOMAIN_DEVICE_FLAG_HOSTDEV | + VIR_DOMAIN_DEVICE_FLAG_LEASE | + VIR_DOMAIN_DEVICE_FLAG_CONTROLLER | + VIR_DOMAIN_DEVICE_FLAG_CHR | + VIR_DOMAIN_DEVICE_FLAG_FS | + VIR_DOMAIN_DEVICE_FLAG_RNG | + VIR_DOMAIN_DEVICE_FLAG_MEMORY | + VIR_DOMAIN_DEVICE_FLAG_REDIRDEV | + VIR_DOMAIN_DEVICE_FLAG_SHMEM | + VIR_DOMAIN_DEVICE_FLAG_WATCHDOG | + VIR_DOMAIN_DEVICE_FLAG_INPUT | + VIR_DOMAIN_DEVICE_FLAG_VSOCK | + VIR_DOMAIN_DEVICE_FLAG_TPM | + VIR_DOMAIN_DEVICE_FLAG_MEMBALLOON, + }; testDriver *ret; if (testDriverInitialize() < 0) @@ -463,7 +508,7 @@ testDriverNew(void) return NULL; if (!(ret->xmlopt = virDomainXMLOptionNew(&config, &privatecb, &ns, - NULL, NULL, NULL)) || + NULL, NULL, &deviceOps)) || !(ret->eventState = virObjectEventStateNew()) || !(ret->ifaces = virInterfaceObjListNew()) || !(ret->domains = virDomainObjListNew()) || -- 2.35.1

Signed-off-by: Luke Yue <lukedyue@gmail.com> --- As persistent_state and is bool type and its default value is false, so I guess it's fine that it's not explicitly assigned with false. link to context: https://listman.redhat.com/archives/libvir-list/2021-November/msg00874.html --- src/conf/domain_conf.c | 67 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 6 ++++ src/libvirt_private.syms | 2 ++ 3 files changed, 75 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e19e3deb17..27643cab16 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16768,6 +16768,73 @@ virDomainVsockDefEquals(const virDomainVsockDef *a, } +static bool +virDomainTPMDefEquals(const virDomainTPMDef *a, + const virDomainTPMDef *b) +{ + if (a->type != b->type) + return false; + + if (a->model != b->model && a->model != VIR_DOMAIN_TPM_MODEL_DEFAULT) + return false; + + if (a->version != b->version && a->version != VIR_DOMAIN_TPM_MODEL_DEFAULT) + return false; + + if (a->type == VIR_DOMAIN_TPM_TYPE_PASSTHROUGH) { + if (STRNEQ_NULLABLE(a->data.passthrough.source->data.file.path, + b->data.passthrough.source->data.file.path)) + return false; + } else { + if (a->data.emulator.hassecretuuid != b->data.emulator.hassecretuuid) + return false; + + if (a->data.emulator.hassecretuuid == true && + memcmp(a->data.emulator.secretuuid, + b->data.emulator.secretuuid, + VIR_UUID_BUFLEN)) + return false; + + if (a->data.emulator.persistent_state != + b->data.emulator.persistent_state) + return false; + } + + if (a->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + !virDomainDeviceInfoAddressIsEqual(&a->info, &b->info)) + return false; + + return true; +} + + +ssize_t +virDomainTPMDefFind(const virDomainDef *def, + const virDomainTPMDef *tpm) +{ + size_t i; + + for (i = 0; i < def->ntpms; i++) { + if (virDomainTPMDefEquals(tpm, def->tpms[i])) + return i; + } + + return -1; +} + + +virDomainTPMDef * +virDomainTPMDefRemove(virDomainDef *def, + size_t idx) +{ + virDomainTPMDef *ret = def->tpms[idx]; + + VIR_DELETE_ELEMENT(def->tpms, idx, def->ntpms); + + return ret; +} + + char * virDomainDefGetDefaultEmulator(virDomainDef *def, virCaps *caps) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3bb1092b60..89031639cb 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3941,6 +3941,12 @@ bool virDomainVsockDefEquals(const virDomainVsockDef *a, const virDomainVsockDef *b) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; +ssize_t virDomainTPMDefFind(const virDomainDef *def, + const virDomainTPMDef *tpm) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; +virDomainTPMDef *virDomainTPMDefRemove(virDomainDef *def, size_t idx) + ATTRIBUTE_NONNULL(1); + VIR_ENUM_DECL(virDomainTaint); VIR_ENUM_DECL(virDomainTaintMessage); VIR_ENUM_DECL(virDomainVirt); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index abdc8eaef7..b6b8606063 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -667,7 +667,9 @@ virDomainTimerTrackTypeFromString; virDomainTimerTrackTypeToString; virDomainTPMBackendTypeFromString; virDomainTPMBackendTypeToString; +virDomainTPMDefFind; virDomainTPMDefFree; +virDomainTPMDefRemove; virDomainTPMModelTypeFromString; virDomainTPMModelTypeToString; virDomainTPMPcrBankTypeFromString; -- 2.35.1

libxl / LXC / QEMU drivers share some common codes in their DomainDetachDeviceConfig functions, so extract them to domain_conf and use them with xmlopt etc to deduplicate the bigger function. At the same time, this will enable test driver to test these functions in the future. Signed-off-by: Luke Yue <lukedyue@gmail.com> --- Compare to the v3, I remove the random comments, and align the error messages, also add virDomainDetachChrDeviceConfig by using xmlopt. Then I got a lot of choices here: 1. Just cleanup these functions and using them in drivers, just like what I did in the previous patch. 2. Add a bigger de-duplicated function to de-duplicate the function in libxl / LXC / QEMU drivers, and this is what I choose in this patch. 3. Merge all the functions into the bigger one, instead of splitting them This would still de-duplicate the functions in libxl / LXC / QEMU drivers. I choose the second here as I think there would be a situation that both these single device detach functions and the bigger function would be used in drivers. --- src/conf/domain_conf.c | 487 +++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 78 +++++++ src/libvirt_private.syms | 18 ++ src/libxl/libxl_driver.c | 73 +----- src/lxc/lxc_driver.c | 62 +---- src/qemu/qemu_driver.c | 207 +---------------- 6 files changed, 610 insertions(+), 315 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 27643cab16..ab2e1f2e36 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -31576,3 +31576,490 @@ virDomainObjGetMessages(virDomainObj *vm, return rv; } + + +int +virDomainDetachDiskDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainDiskDef *disk; + virDomainDiskDef *det_disk; + + disk = dev->data.disk; + if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) { + virReportError(VIR_ERR_DEVICE_MISSING, + _("no matching disk device %s was found"), + disk->dst); + return -1; + } + + virDomainDiskDefFree(det_disk); + + return 0; +} + + +int +virDomainDetachNetDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainNetDef *net; + int idx; + + net = dev->data.net; + if ((idx = virDomainNetFindIdx(vmdef, net)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching net device was found")); + return -1; + } + + virDomainNetDefFree(virDomainNetRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachSoundDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainSoundDef *sound; + int idx; + + sound = dev->data.sound; + if ((idx = virDomainSoundDefFind(vmdef, sound)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching sound device was found")); + return -1; + } + + virDomainSoundDefFree(virDomainSoundDefRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachHostdevDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainHostdevDef *hostdev; + virDomainHostdevDef *det_hostdev; + int idx; + + hostdev = dev->data.hostdev; + if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching hostdev device was found")); + return -1; + } + + virDomainHostdevDefFree(virDomainHostdevRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachLeaseDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainLeaseDef *lease; + virDomainLeaseDef *det_lease; + + lease = dev->data.lease; + if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) { + virReportError(VIR_ERR_DEVICE_MISSING, + _("no matching lease %s in lockspace %s was found"), + lease->key, NULLSTR(lease->lockspace)); + return -1; + } + + virDomainLeaseDefFree(det_lease); + + return 0; +} + + +int +virDomainDetachControllerDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainControllerDef *cont; + int idx; + + cont = dev->data.controller; + if ((idx = virDomainControllerFind(vmdef, cont->type, cont->idx)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching controller device was found")); + return -1; + } + + virDomainControllerDefFree(virDomainControllerRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachFSDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainFSDef *fs; + int idx; + + fs = dev->data.fs; + if ((idx = virDomainFSIndexByName(vmdef, fs->dst)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching filesystem device was found")); + return -1; + } + + virDomainFSDefFree(virDomainFSRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachRNGDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + int idx; + + if ((idx = virDomainRNGFind(vmdef, dev->data.rng)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching RNG device was found")); + return -1; + } + + virDomainRNGDefFree(virDomainRNGRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachMemoryDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + virDomainMemoryDef *mem; + int idx; + + if ((idx = virDomainMemoryFindInactiveByDef(vmdef, + dev->data.memory)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching memory device was found")); + return -1; + } + + mem = virDomainMemoryRemove(vmdef, idx); + vmdef->mem.cur_balloon -= mem->size; + virDomainMemoryDefFree(mem); + + return 0; +} + + +int +virDomainDetachRedirdevDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + int idx; + + if ((idx = virDomainRedirdevDefFind(vmdef, + dev->data.redirdev)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching redirdev was found")); + return -1; + } + + virDomainRedirdevDefFree(virDomainRedirdevDefRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachShmemDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + int idx; + + if ((idx = virDomainShmemDefFind(vmdef, dev->data.shmem)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching shmem device was found")); + return -1; + } + + virDomainShmemDefFree(virDomainShmemDefRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachWatchdogDeviceConfig(virDomainDef *vmdef) +{ + if (!vmdef->watchdog) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching watch dog device was found")); + return -1; + } + + virDomainWatchdogDefFree(vmdef->watchdog); + vmdef->watchdog = NULL; + + return 0; +} + + +int +virDomainDetachInputDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + int idx; + + if ((idx = virDomainInputDefFind(vmdef, dev->data.input)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching input device was found")); + return -1; + } + + virDomainInputDefFree(virDomainInputDefRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachVsockDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + if (!vmdef->vsock || + !virDomainVsockDefEquals(dev->data.vsock, vmdef->vsock)) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching vsock device was found")); + return -1; + } + + virDomainVsockDefFree(vmdef->vsock); + vmdef->vsock = NULL; + + return 0; +} + + +int +virDomainDetachTPMDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev) +{ + int idx; + + if ((idx = virDomainTPMDefFind(vmdef, dev->data.tpm)) < 0) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching tpm device was found")); + return -1; + } + + virDomainTPMDefFree(virDomainTPMDefRemove(vmdef, idx)); + + return 0; +} + + +int +virDomainDetachChrDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + virDomainXMLOption *xmlopt, + unsigned int flags) +{ + virDomainChrDef *chr; + + if (xmlopt && xmlopt->deviceOps.detachChr) { + return xmlopt->deviceOps.detachChr(vmdef, dev, flags); + } + + if (!(chr = virDomainChrRemove(vmdef, dev->data.chr))) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching char device was found")); + return -1; + } + + virDomainChrDefFree(chr); + + return 0; +} + + +int +virDomainDetachMemballoonDeviceConfig(virDomainDef *vmdef, + virDomainXMLOption *xmlopt, + unsigned int flags) +{ + if (xmlopt && xmlopt->deviceOps.detachMemballoon) { + return xmlopt->deviceOps.detachMemballoon(vmdef, NULL, flags); + } + + if (!vmdef->memballoon) { + virReportError(VIR_ERR_DEVICE_MISSING, "%s", + _("no matching memballoon device was found")); + return -1; + } + + virDomainMemballoonDefFree(vmdef->memballoon); + vmdef->memballoon = NULL; + + return 0; +} + + +int +virDomainDetachDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + void *parseOpaque, + unsigned int flags, + unsigned int parse_flags, + virDomainXMLOption *xmlopt) +{ + int ret = 0; + + if (!(xmlopt->deviceOps.detachFlags & (1 << dev->type))) { + ret = -1; + goto error; + } + + switch ((virDomainDeviceType) dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + if (virDomainDetachDiskDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_NET: + if (virDomainDetachNetDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_SOUND: + if (virDomainDetachSoundDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_HOSTDEV: + if (virDomainDetachHostdevDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_LEASE: + if (virDomainDetachLeaseDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_CONTROLLER: + if (virDomainDetachControllerDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_FS: + if (virDomainDetachFSDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_RNG: + if (virDomainDetachRNGDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_MEMORY: + if (virDomainDetachMemoryDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_REDIRDEV: + if (virDomainDetachRedirdevDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_SHMEM: + if (virDomainDetachShmemDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_WATCHDOG: + if (virDomainDetachWatchdogDeviceConfig(vmdef) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_INPUT: + if (virDomainDetachInputDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_VSOCK: + if (virDomainDetachVsockDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_CHR: + if (virDomainDetachChrDeviceConfig(vmdef, dev, xmlopt, flags) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_TPM: + if (virDomainDetachTPMDeviceConfig(vmdef, dev) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_MEMBALLOON: + if (virDomainDetachMemballoonDeviceConfig(vmdef, xmlopt, flags) < 0) + return -1; + + break; + + case VIR_DOMAIN_DEVICE_VIDEO: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_SMARTCARD: + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_NONE: + case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: + case VIR_DOMAIN_DEVICE_LAST: + ret = -1; + goto error; + } + + if (parseOpaque) { + if (virDomainDefPostParse(vmdef, parse_flags, xmlopt, parseOpaque) < 0) + return -1; + } + + error: + if (ret < 0) { + /* When using in test driver, flags may + contain VIR_DOMAIN_AFFECT_LIVE */ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("%sdetach of device '%s' is not supported"), + (!(flags & VIR_DOMAIN_AFFECT_LIVE)) ? "persistent " : "", + virDomainDeviceTypeToString(dev->type)); + return -1; + } + return 0; +} diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 89031639cb..5348773668 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -4311,3 +4311,81 @@ int virDomainObjGetMessages(virDomainObj *vm, char ***msgs, unsigned int flags); + +int +virDomainDetachDiskDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachNetDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachSoundDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachHostdevDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachLeaseDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachControllerDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachFSDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachRNGDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachMemoryDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachRedirdevDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachShmemDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachWatchdogDeviceConfig(virDomainDef *vmdef); + +int +virDomainDetachInputDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachVsockDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachTPMDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev); + +int +virDomainDetachMemballoonDeviceConfig(virDomainDef *vmdef, + virDomainXMLOption *xmlopt, + unsigned int flags); + +int +virDomainDetachChrDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + virDomainXMLOption *xmlopt, + unsigned int flags); + +int +virDomainDetachDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + void *parseOpaque, + unsigned int flags, + unsigned int parse_flags, + virDomainXMLOption *xmlopt); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b6b8606063..1b0b3d357d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -352,6 +352,24 @@ virDomainDefSetVcpus; virDomainDefSetVcpusMax; virDomainDefVcpuOrderClear; virDomainDeleteConfig; +virDomainDetachChrDeviceConfig; +virDomainDetachControllerDeviceConfig; +virDomainDetachDeviceConfig; +virDomainDetachDiskDeviceConfig; +virDomainDetachFSDeviceConfig; +virDomainDetachHostdevDeviceConfig; +virDomainDetachInputDeviceConfig; +virDomainDetachLeaseDeviceConfig; +virDomainDetachMemballoonDeviceConfig; +virDomainDetachMemoryDeviceConfig; +virDomainDetachNetDeviceConfig; +virDomainDetachRedirdevDeviceConfig; +virDomainDetachRNGDeviceConfig; +virDomainDetachShmemDeviceConfig; +virDomainDetachSoundDeviceConfig; +virDomainDetachTPMDeviceConfig; +virDomainDetachVsockDeviceConfig; +virDomainDetachWatchdogDeviceConfig; virDomainDeviceAliasIsUserAlias; virDomainDeviceDefCopy; virDomainDeviceDefFree; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 2d9385654c..26e02497b4 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3897,68 +3897,14 @@ libxlDomainDetachDeviceLive(libxlDriverPrivate *driver, static int -libxlDomainDetachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) +libxlDomainDetachDeviceConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + unsigned int flags, + unsigned int parse_flags, + virDomainXMLOption *xmlopt) { - virDomainDiskDef *disk; - virDomainDiskDef *detach; - virDomainHostdevDef *hostdev; - virDomainHostdevDef *det_hostdev; - virDomainControllerDef *cont; - virDomainControllerDef *det_cont; - virDomainNetDef *net; - int idx; - - switch (dev->type) { - case VIR_DOMAIN_DEVICE_DISK: - disk = dev->data.disk; - if (!(detach = virDomainDiskRemoveByName(vmdef, disk->dst))) { - virReportError(VIR_ERR_INVALID_ARG, - _("no target device %s"), disk->dst); - return -1; - } - virDomainDiskDefFree(detach); - break; - - case VIR_DOMAIN_DEVICE_CONTROLLER: - cont = dev->data.controller; - if ((idx = virDomainControllerFind(vmdef, cont->type, - cont->idx)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("device not present in domain configuration")); - return -1; - } - det_cont = virDomainControllerRemove(vmdef, idx); - virDomainControllerDefFree(det_cont); - break; - - case VIR_DOMAIN_DEVICE_NET: - net = dev->data.net; - if ((idx = virDomainNetFindIdx(vmdef, net)) < 0) - return -1; - - /* this is guaranteed to succeed */ - virDomainNetDefFree(virDomainNetRemove(vmdef, idx)); - break; - - case VIR_DOMAIN_DEVICE_HOSTDEV: { - hostdev = dev->data.hostdev; - if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("device not present in domain configuration")); - return -1; - } - virDomainHostdevRemove(vmdef, idx); - virDomainHostdevDefFree(det_hostdev); - break; - } - - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("persistent detach of device is not supported")); - return -1; - } - - return 0; + return virDomainDetachDeviceConfig(vmdef, dev, NULL, flags, + parse_flags, xmlopt); } static int @@ -4190,7 +4136,10 @@ libxlDomainDetachDeviceFlags(virDomainPtr dom, const char *xml, if (!(vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL))) goto endjob; - if (libxlDomainDetachDeviceConfig(vmdef, dev) < 0) + if (libxlDomainDetachDeviceConfig(vmdef, dev, flags, + VIR_DOMAIN_DEF_PARSE_INACTIVE | + VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE, + driver->xmlopt) < 0) goto endjob; } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 3d17b87e8c..b6eb839f4f 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3093,58 +3093,13 @@ lxcDomainUpdateDeviceConfig(virDomainDef *vmdef, static int lxcDomainDetachDeviceConfig(virDomainDef *vmdef, - virDomainDeviceDef *dev) + virDomainDeviceDef *dev, + unsigned int flags, + unsigned int parse_flags, + virDomainXMLOption *xmlopt) { - int ret = -1; - virDomainDiskDef *disk; - virDomainDiskDef *det_disk; - virDomainNetDef *net; - virDomainHostdevDef *hostdev; - virDomainHostdevDef *det_hostdev; - int idx; - - switch (dev->type) { - case VIR_DOMAIN_DEVICE_DISK: - disk = dev->data.disk; - if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) { - virReportError(VIR_ERR_INVALID_ARG, - _("no target device %s"), disk->dst); - return -1; - } - virDomainDiskDefFree(det_disk); - ret = 0; - break; - - case VIR_DOMAIN_DEVICE_NET: - net = dev->data.net; - if ((idx = virDomainNetFindIdx(vmdef, net)) < 0) - return -1; - - /* this is guaranteed to succeed */ - virDomainNetDefFree(virDomainNetRemove(vmdef, idx)); - ret = 0; - break; - - case VIR_DOMAIN_DEVICE_HOSTDEV: { - hostdev = dev->data.hostdev; - if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("device not present in domain configuration")); - return -1; - } - virDomainHostdevRemove(vmdef, idx); - virDomainHostdevDefFree(det_hostdev); - ret = 0; - break; - } - - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("persistent detach of device is not supported")); - break; - } - - return ret; + return virDomainDetachDeviceConfig(vmdef, dev, NULL, flags, + parse_flags, xmlopt); } @@ -4475,7 +4430,10 @@ static int lxcDomainDetachDeviceFlags(virDomainPtr dom, if (!vmdef) goto endjob; - if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev_copy)) < 0) + if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev, flags, + VIR_DOMAIN_DEF_PARSE_INACTIVE | + VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE, + driver->xmlopt)) < 0) goto endjob; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 864ea10685..d625c9be0e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7338,207 +7338,12 @@ static int qemuDomainDetachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev, virQEMUCaps *qemuCaps, + unsigned int flags, unsigned int parse_flags, virDomainXMLOption *xmlopt) { - virDomainDiskDef *disk; - virDomainDiskDef *det_disk; - virDomainNetDef *net; - virDomainSoundDef *sound; - virDomainHostdevDef *hostdev; - virDomainHostdevDef *det_hostdev; - virDomainLeaseDef *lease; - virDomainLeaseDef *det_lease; - virDomainControllerDef *cont; - virDomainControllerDef *det_cont; - virDomainChrDef *chr; - virDomainFSDef *fs; - virDomainMemoryDef *mem; - int idx; - - switch ((virDomainDeviceType)dev->type) { - case VIR_DOMAIN_DEVICE_DISK: - disk = dev->data.disk; - if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) { - virReportError(VIR_ERR_DEVICE_MISSING, - _("no target device %s"), disk->dst); - return -1; - } - virDomainDiskDefFree(det_disk); - break; - - case VIR_DOMAIN_DEVICE_NET: - net = dev->data.net; - if ((idx = virDomainNetFindIdx(vmdef, net)) < 0) - return -1; - - /* this is guaranteed to succeed */ - virDomainNetDefFree(virDomainNetRemove(vmdef, idx)); - break; - - case VIR_DOMAIN_DEVICE_SOUND: - sound = dev->data.sound; - if ((idx = virDomainSoundDefFind(vmdef, sound)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("device not present in domain configuration")); - return -1; - } - virDomainSoundDefFree(virDomainSoundDefRemove(vmdef, idx)); - break; - - case VIR_DOMAIN_DEVICE_HOSTDEV: { - hostdev = dev->data.hostdev; - if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("device not present in domain configuration")); - return -1; - } - virDomainHostdevRemove(vmdef, idx); - virDomainHostdevDefFree(det_hostdev); - break; - } - - case VIR_DOMAIN_DEVICE_LEASE: - lease = dev->data.lease; - if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) { - virReportError(VIR_ERR_DEVICE_MISSING, - _("Lease %s in lockspace %s does not exist"), - lease->key, NULLSTR(lease->lockspace)); - return -1; - } - virDomainLeaseDefFree(det_lease); - break; - - case VIR_DOMAIN_DEVICE_CONTROLLER: - cont = dev->data.controller; - if ((idx = virDomainControllerFind(vmdef, cont->type, - cont->idx)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("device not present in domain configuration")); - return -1; - } - det_cont = virDomainControllerRemove(vmdef, idx); - virDomainControllerDefFree(det_cont); - - break; - - case VIR_DOMAIN_DEVICE_CHR: - if (!(chr = qemuDomainChrRemove(vmdef, dev->data.chr))) - return -1; - - virDomainChrDefFree(chr); - break; - - case VIR_DOMAIN_DEVICE_FS: - fs = dev->data.fs; - idx = virDomainFSIndexByName(vmdef, fs->dst); - if (idx < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("no matching filesystem device was found")); - return -1; - } - - fs = virDomainFSRemove(vmdef, idx); - virDomainFSDefFree(fs); - break; - - case VIR_DOMAIN_DEVICE_RNG: - if ((idx = virDomainRNGFind(vmdef, dev->data.rng)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("no matching RNG device was found")); - return -1; - } - - virDomainRNGDefFree(virDomainRNGRemove(vmdef, idx)); - break; - - case VIR_DOMAIN_DEVICE_MEMORY: - if ((idx = virDomainMemoryFindInactiveByDef(vmdef, - dev->data.memory)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("matching memory device was not found")); - return -1; - } - mem = virDomainMemoryRemove(vmdef, idx); - vmdef->mem.cur_balloon -= mem->size; - virDomainMemoryDefFree(mem); - break; - - case VIR_DOMAIN_DEVICE_REDIRDEV: - if ((idx = virDomainRedirdevDefFind(vmdef, - dev->data.redirdev)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("no matching redirdev was not found")); - return -1; - } - - virDomainRedirdevDefFree(virDomainRedirdevDefRemove(vmdef, idx)); - break; - - case VIR_DOMAIN_DEVICE_SHMEM: - if ((idx = virDomainShmemDefFind(vmdef, dev->data.shmem)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("matching shmem device was not found")); - return -1; - } - - virDomainShmemDefFree(virDomainShmemDefRemove(vmdef, idx)); - break; - - - case VIR_DOMAIN_DEVICE_WATCHDOG: - if (!vmdef->watchdog) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("domain has no watchdog")); - return -1; - } - virDomainWatchdogDefFree(vmdef->watchdog); - vmdef->watchdog = NULL; - break; - - case VIR_DOMAIN_DEVICE_INPUT: - if ((idx = virDomainInputDefFind(vmdef, dev->data.input)) < 0) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("matching input device not found")); - return -1; - } - - virDomainInputDefFree(virDomainInputDefRemove(vmdef, idx)); - break; - - case VIR_DOMAIN_DEVICE_VSOCK: - if (!vmdef->vsock || - !virDomainVsockDefEquals(dev->data.vsock, vmdef->vsock)) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("matching vsock device not found")); - return -1; - } - virDomainVsockDefFree(vmdef->vsock); - vmdef->vsock = NULL; - break; - - case VIR_DOMAIN_DEVICE_VIDEO: - case VIR_DOMAIN_DEVICE_GRAPHICS: - case VIR_DOMAIN_DEVICE_HUB: - case VIR_DOMAIN_DEVICE_SMARTCARD: - case VIR_DOMAIN_DEVICE_MEMBALLOON: - case VIR_DOMAIN_DEVICE_NVRAM: - case VIR_DOMAIN_DEVICE_NONE: - case VIR_DOMAIN_DEVICE_TPM: - case VIR_DOMAIN_DEVICE_PANIC: - case VIR_DOMAIN_DEVICE_IOMMU: - case VIR_DOMAIN_DEVICE_AUDIO: - case VIR_DOMAIN_DEVICE_LAST: - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, - _("persistent detach of device '%s' is not supported"), - virDomainDeviceTypeToString(dev->type)); - return -1; - } - - if (virDomainDefPostParse(vmdef, parse_flags, xmlopt, qemuCaps) < 0) - return -1; - - return 0; + return virDomainDetachDeviceConfig(vmdef, dev, qemuCaps, flags, + parse_flags, xmlopt); } static int @@ -7982,8 +7787,8 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriver *driver, if (!vmdef) goto cleanup; - if (qemuDomainDetachDeviceConfig(vmdef, dev_copy, priv->qemuCaps, - parse_flags, + if (qemuDomainDetachDeviceConfig(vmdef, dev, priv->qemuCaps, + flags, parse_flags, driver->xmlopt) < 0) goto cleanup; } @@ -8052,7 +7857,7 @@ qemuDomainDetachDeviceAliasLiveAndConfig(virQEMUDriver *driver, if (virDomainDefFindDevice(vmdef, alias, &dev, true) < 0) return -1; - if (qemuDomainDetachDeviceConfig(vmdef, &dev, priv->qemuCaps, + if (qemuDomainDetachDeviceConfig(vmdef, &dev, priv->qemuCaps, flags, parse_flags, driver->xmlopt) < 0) return -1; } -- 2.35.1

Introduce testDomainChgDevice for further development (just like what we did for IOThread). And introduce testDomainDetachDeviceLiveAndConfig for detaching devices. Also as we implement testDomainChgDevice for both DetachDeviceFlags and DetachDeviceAlias, we could easily implement virDomainDetachDeviceAlias and virDomainDetachDevice. Signed-off-by: Luke Yue <lukedyue@gmail.com> --- src/test/test_driver.c | 149 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 2380c37ddb..65ab412b36 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -10014,6 +10014,152 @@ testConnectGetAllDomainStats(virConnectPtr conn, return ret; } + +static int +testDomainDetachDeviceLiveAndConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + unsigned int flags, + unsigned int parse_flags, + virDomainXMLOption *xmlopt) +{ + /* Though the function called virDomainDetachDeviceConfig, for + test driver, it could be for both live and config */ + return virDomainDetachDeviceConfig(vmdef, dev, NULL, flags, + parse_flags, xmlopt); +} + +static int +testDomainDoChgDevice(testDriver *driver, + virDomainDeviceAction action, + const char *xml, + const char *alias, + virDomainDef *def, + unsigned int flags) +{ + virDomainDeviceDef *dev = NULL; + unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE; + int ret = -1; + + if (action == VIR_DOMAIN_DEVICE_ACTION_DETACH) + parse_flags |= VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; + + if (xml) { + if (!(dev = virDomainDeviceDefParse(xml, def, driver->xmlopt, + driver->caps, parse_flags))) + goto cleanup; + } else if (alias) { + dev = g_new0(virDomainDeviceDef, 1); + if (virDomainDefFindDevice(def, alias, dev, true) < 0) + goto cleanup; + } + + if (dev == NULL) + goto cleanup; + + switch (action) { + case VIR_DOMAIN_DEVICE_ACTION_ATTACH: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("attaching devices is not supported")); + goto cleanup; + break; + + case VIR_DOMAIN_DEVICE_ACTION_DETACH: + if (testDomainDetachDeviceLiveAndConfig(def, dev, flags, parse_flags, + driver->xmlopt) < 0) + goto cleanup; + break; + + case VIR_DOMAIN_DEVICE_ACTION_UPDATE: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("updating devices is not supported")); + goto cleanup; + break; + } + + ret = 0; + + cleanup: + if (xml) { + virDomainDeviceDefFree(dev); + } else { + g_free(dev); + } + return ret; +} + +static int +testDomainChgDevice(virDomainPtr dom, + virDomainDeviceAction action, + const char *xml, + const char *alias, + unsigned int flags) +{ + testDriver *driver = dom->conn->privateData; + virDomainObj *vm = NULL; + virDomainDef *def; + virDomainDef *persistentDef; + + int ret = -1; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (!(vm = testDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainObjUpdateModificationImpact(vm, &flags) < 0) + goto cleanup; + + if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) + goto cleanup; + + if (def) { + if (testDomainDoChgDevice(driver, action, xml, + alias, def, flags) < 0) { + goto cleanup; + } + } + + if (persistentDef) { + if (testDomainDoChgDevice(driver, action, xml, + alias, persistentDef, flags) < 0) { + goto cleanup; + } + } + + ret = 0; + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + +static int +testDomainDetachDeviceFlags(virDomainPtr dom, + const char *xml, + unsigned int flags) +{ + return testDomainChgDevice(dom, VIR_DOMAIN_DEVICE_ACTION_DETACH, + xml, NULL, flags); +} + +static int +testDomainDetachDeviceAlias(virDomainPtr dom, + const char *alias, + unsigned int flags) +{ + return testDomainChgDevice(dom, VIR_DOMAIN_DEVICE_ACTION_DETACH, + NULL, alias, flags); +} + +static int +testDomainDetachDevice(virDomainPtr dom, + const char *xml) +{ + return testDomainDetachDeviceFlags(dom, xml, + VIR_DOMAIN_AFFECT_LIVE); +} + /* * Test driver */ @@ -10111,6 +10257,9 @@ static virHypervisorDriver testHypervisorDriver = { .domainFSFreeze = testDomainFSFreeze, /* 5.7.0 */ .domainFSThaw = testDomainFSThaw, /* 5.7.0 */ .domainFSTrim = testDomainFSTrim, /* 5.7.0 */ + .domainDetachDevice = testDomainDetachDevice, /* 8.1.0 */ + .domainDetachDeviceAlias = testDomainDetachDeviceAlias, /* 8.1.0 */ + .domainDetachDeviceFlags = testDomainDetachDeviceFlags, /* 8.1.0 */ .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */ .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */ .domainGetDiskErrors = testDomainGetDiskErrors, /* 5.4.0 */ -- 2.35.1

Also add some device xml to generichotplugdata for testing purpose, and add the forgotten testdomfc5.xml to meson.build. Signed-off-by: Luke Yue <lukedyue@gmail.com> --- examples/xml/test/meson.build | 1 + examples/xml/test/testdomfc5.xml | 54 +++++++++++++++++++ examples/xml/test/testnodeinline.xml | 54 +++++++++++++++++++ .../generichotplug-controller.xml | 1 + .../generichotplug-disk-cdrom.xml | 5 ++ .../generichotplug-filesystem.xml | 6 +++ .../generichotplug-hostdev.xml | 5 ++ .../generichotplug-input.xml | 1 + .../generichotplug-interface.xml | 6 +++ .../generichotplug-lease.xml | 5 ++ .../generichotplug-memballoon.xml | 3 ++ .../generichotplug-memory.xml | 6 +++ .../generichotplugdata/generichotplug-rng.xml | 4 ++ .../generichotplug-shmem.xml | 4 ++ .../generichotplug-sound.xml | 3 ++ .../generichotplugdata/generichotplug-tpm.xml | 5 ++ .../generichotplug-vsock.xml | 3 ++ .../generichotplug-watchdog.xml | 1 + 18 files changed, 167 insertions(+) create mode 100644 tests/generichotplugdata/generichotplug-controller.xml create mode 100644 tests/generichotplugdata/generichotplug-disk-cdrom.xml create mode 100644 tests/generichotplugdata/generichotplug-filesystem.xml create mode 100644 tests/generichotplugdata/generichotplug-hostdev.xml create mode 100644 tests/generichotplugdata/generichotplug-input.xml create mode 100644 tests/generichotplugdata/generichotplug-interface.xml create mode 100644 tests/generichotplugdata/generichotplug-lease.xml create mode 100644 tests/generichotplugdata/generichotplug-memballoon.xml create mode 100644 tests/generichotplugdata/generichotplug-memory.xml create mode 100644 tests/generichotplugdata/generichotplug-rng.xml create mode 100644 tests/generichotplugdata/generichotplug-shmem.xml create mode 100644 tests/generichotplugdata/generichotplug-sound.xml create mode 100644 tests/generichotplugdata/generichotplug-tpm.xml create mode 100644 tests/generichotplugdata/generichotplug-vsock.xml create mode 100644 tests/generichotplugdata/generichotplug-watchdog.xml diff --git a/examples/xml/test/meson.build b/examples/xml/test/meson.build index 89ebf03a7b..4a7e357d47 100644 --- a/examples/xml/test/meson.build +++ b/examples/xml/test/meson.build @@ -3,6 +3,7 @@ install_data( 'testdev.xml', 'testnodeinline.xml', 'testdomfc4.xml', + 'testdomfc5.xml', 'testdomfv0.xml', 'testnode.xml', 'testnetdef.xml', diff --git a/examples/xml/test/testdomfc5.xml b/examples/xml/test/testdomfc5.xml index a8afc211f6..3b9edb9da9 100644 --- a/examples/xml/test/testdomfc5.xml +++ b/examples/xml/test/testdomfc5.xml @@ -29,6 +29,12 @@ <mac address='00:16:3e:5d:c7:26'/> <script path='vif-bridge'/> </interface> + <interface type='network'> + <source network='testbrigde' /> + <mac address='00:11:22:33:44:55' /> + <model type='virtio' /> + <alias name='ua-testNIC' /> + </interface> <disk type='file'> <source file='/root/fv0'/> <target dev='hda'/> @@ -36,6 +42,7 @@ <disk type='block' device='cdrom'> <source dev='/dev/sr0'/> <target dev='hdb' bus='ide'/> + <alias name='ua-testCD' /> <readonly/> </disk> <disk type='file' device='floppy'> @@ -47,5 +54,52 @@ <target dev='sda' bus='scsi'/> </disk> <graphics type='vnc' port='5904'/> + <sound model='ich6'> + <codec type='micro'/> + </sound> + <hostdev mode='capabilities' type='storage'> + <source> + <block>/dev/sdf1</block> + </source> + </hostdev> + <lease> + <lockspace>testarea</lockspace> + <key>testkey</key> + <target path='/root/test/lease/path' offset='1024'/> + </lease> + <controller type='ide' index='0'/> + <filesystem type='file' accessmode='passthrough'> + <driver type='loop' format='raw'/> + <source file='/root/test/guest.img'/> + <target dir='/root/libvirt/test'/> + <readonly/> + </filesystem> + <rng model='virtio'> + <rate period="2000" bytes="1234" /> + <backend model='builtin' /> + </rng> + <memory model='dimm' access='private' discard='yes'> + <target> + <size unit='KiB'>524287</size> + <node>0</node> + </target> + </memory> + <shmem name='my_shmem0' role='peer'> + <model type='ivshmem-plain'/> + <size unit='M'>4</size> + </shmem> + <watchdog model='i6300esb'/> + <input type='mouse' bus='virtio'/> + <vsock model='virtio'> + <cid auto='no' address='3'/> + </vsock> + <tpm model='tpm-tis'> + <backend type='emulator' version='2.0'> + <encryption secret='6dd3e4a5-1d76-44ce-961f-f119f5aad935'/> + </backend> + </tpm> + <memballoon model='virtio'> + <stats period='10' /> + </memballoon> </devices> </domain> diff --git a/examples/xml/test/testnodeinline.xml b/examples/xml/test/testnodeinline.xml index 9165d9302d..1124146f73 100644 --- a/examples/xml/test/testnodeinline.xml +++ b/examples/xml/test/testnodeinline.xml @@ -117,6 +117,12 @@ <mac address='00:16:3e:5d:c7:26'/> <script path='vif-bridge'/> </interface> + <interface type='network'> + <source network='testbrigde' /> + <mac address='00:11:22:33:44:55' /> + <model type='virtio' /> + <alias name='ua-testNIC' /> + </interface> <disk type='file'> <source file='/root/fv0'/> <target dev='hda'/> @@ -124,6 +130,7 @@ <disk type='block' device='cdrom'> <source dev='/dev/sr0'/> <target dev='hdb' bus='ide'/> + <alias name='ua-testCD' /> <readonly/> </disk> <disk type='file' device='floppy'> @@ -135,6 +142,53 @@ <target dev='sda' bus='scsi'/> </disk> <graphics type='vnc' port='5904'/> + <sound model='ich6'> + <codec type='micro'/> + </sound> + <hostdev mode='capabilities' type='storage'> + <source> + <block>/dev/sdf1</block> + </source> + </hostdev> + <lease> + <lockspace>testarea</lockspace> + <key>testkey</key> + <target path='/root/test/lease/path' offset='1024'/> + </lease> + <controller type='ide' index='0'/> + <filesystem type='file' accessmode='passthrough'> + <driver type='loop' format='raw'/> + <source file='/root/test/guest.img'/> + <target dir='/root/libvirt/test'/> + <readonly/> + </filesystem> + <rng model='virtio'> + <rate period="2000" bytes="1234" /> + <backend model='builtin' /> + </rng> + <memory model='dimm' access='private' discard='yes'> + <target> + <size unit='KiB'>524287</size> + <node>0</node> + </target> + </memory> + <shmem name='my_shmem0' role='peer'> + <model type='ivshmem-plain'/> + <size unit='M'>4</size> + </shmem> + <watchdog model='i6300esb'/> + <input type='mouse' bus='virtio'/> + <vsock model='virtio'> + <cid auto='no' address='3'/> + </vsock> + <tpm model='tpm-tis'> + <backend type='emulator' version='2.0'> + <encryption secret='6dd3e4a5-1d76-44ce-961f-f119f5aad935'/> + </backend> + </tpm> + <memballoon model='virtio'> + <stats period='10' /> + </memballoon> </devices> </domain> <network> diff --git a/tests/generichotplugdata/generichotplug-controller.xml b/tests/generichotplugdata/generichotplug-controller.xml new file mode 100644 index 0000000000..d855bfa17f --- /dev/null +++ b/tests/generichotplugdata/generichotplug-controller.xml @@ -0,0 +1 @@ +<controller type='ide' index='0'/> diff --git a/tests/generichotplugdata/generichotplug-disk-cdrom.xml b/tests/generichotplugdata/generichotplug-disk-cdrom.xml new file mode 100644 index 0000000000..edc90556bb --- /dev/null +++ b/tests/generichotplugdata/generichotplug-disk-cdrom.xml @@ -0,0 +1,5 @@ +<disk type='block' device='cdrom'> + <source dev='/dev/sr0'/> + <target dev='hdb' bus='ide'/> + <readonly/> +</disk> diff --git a/tests/generichotplugdata/generichotplug-filesystem.xml b/tests/generichotplugdata/generichotplug-filesystem.xml new file mode 100644 index 0000000000..cee5ed4ed9 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-filesystem.xml @@ -0,0 +1,6 @@ +<filesystem type='file' accessmode='passthrough'> + <driver type='loop' format='raw'/> + <source file='/root/test/guest.img'/> + <target dir='/root/libvirt/test'/> + <readonly/> +</filesystem> diff --git a/tests/generichotplugdata/generichotplug-hostdev.xml b/tests/generichotplugdata/generichotplug-hostdev.xml new file mode 100644 index 0000000000..e364b50f36 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-hostdev.xml @@ -0,0 +1,5 @@ +<hostdev mode='capabilities' type='storage'> + <source> + <block>/dev/sdf1</block>s + </source> +</hostdev> diff --git a/tests/generichotplugdata/generichotplug-input.xml b/tests/generichotplugdata/generichotplug-input.xml new file mode 100644 index 0000000000..d958f5b931 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-input.xml @@ -0,0 +1 @@ +<input type='mouse' bus='virtio'/> diff --git a/tests/generichotplugdata/generichotplug-interface.xml b/tests/generichotplugdata/generichotplug-interface.xml new file mode 100644 index 0000000000..7e0be80050 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-interface.xml @@ -0,0 +1,6 @@ +<interface type='network'> + <source network='testbrigde' /> + <mac address='00:11:22:33:44:55' /> + <model type='virtio' /> + <alias name='ua-testNIC' /> +</interface> diff --git a/tests/generichotplugdata/generichotplug-lease.xml b/tests/generichotplugdata/generichotplug-lease.xml new file mode 100644 index 0000000000..c53c0c7e7d --- /dev/null +++ b/tests/generichotplugdata/generichotplug-lease.xml @@ -0,0 +1,5 @@ +<lease> + <lockspace>testarea</lockspace> + <key>testkey</key> + <target path='/root/test/lease/path' offset='1024'/> +</lease> diff --git a/tests/generichotplugdata/generichotplug-memballoon.xml b/tests/generichotplugdata/generichotplug-memballoon.xml new file mode 100644 index 0000000000..fde18a9db6 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-memballoon.xml @@ -0,0 +1,3 @@ +<memballoon model='virtio'> + <stats period='10' /> +</memballoon> diff --git a/tests/generichotplugdata/generichotplug-memory.xml b/tests/generichotplugdata/generichotplug-memory.xml new file mode 100644 index 0000000000..49efd4af55 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-memory.xml @@ -0,0 +1,6 @@ +<memory model='dimm' access='private' discard='yes'> + <target> + <size unit='KiB'>524287</size> + <node>0</node> + </target> +</memory> diff --git a/tests/generichotplugdata/generichotplug-rng.xml b/tests/generichotplugdata/generichotplug-rng.xml new file mode 100644 index 0000000000..369f423740 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-rng.xml @@ -0,0 +1,4 @@ +<rng model='virtio'> + <rate period="2000" bytes="1234" /> + <backend model='builtin' /> +</rng> diff --git a/tests/generichotplugdata/generichotplug-shmem.xml b/tests/generichotplugdata/generichotplug-shmem.xml new file mode 100644 index 0000000000..04bf3d9a53 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-shmem.xml @@ -0,0 +1,4 @@ +<shmem name='my_shmem0' role='peer'> + <model type='ivshmem-plain'/> + <size unit='M'>4</size> +</shmem> diff --git a/tests/generichotplugdata/generichotplug-sound.xml b/tests/generichotplugdata/generichotplug-sound.xml new file mode 100644 index 0000000000..cf7323077f --- /dev/null +++ b/tests/generichotplugdata/generichotplug-sound.xml @@ -0,0 +1,3 @@ +<sound model='ich6'> + <codec type='micro'/> +</sound> diff --git a/tests/generichotplugdata/generichotplug-tpm.xml b/tests/generichotplugdata/generichotplug-tpm.xml new file mode 100644 index 0000000000..cc08b7bf6d --- /dev/null +++ b/tests/generichotplugdata/generichotplug-tpm.xml @@ -0,0 +1,5 @@ +<tpm model='tpm-tis'> + <backend type='emulator' version='2.0'> + <encryption secret='6dd3e4a5-1d76-44ce-961f-f119f5aad935'/> + </backend> +</tpm> diff --git a/tests/generichotplugdata/generichotplug-vsock.xml b/tests/generichotplugdata/generichotplug-vsock.xml new file mode 100644 index 0000000000..dda45780c4 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-vsock.xml @@ -0,0 +1,3 @@ +<vsock model='virtio'> + <cid auto='no' address='3'/> +</vsock> diff --git a/tests/generichotplugdata/generichotplug-watchdog.xml b/tests/generichotplugdata/generichotplug-watchdog.xml new file mode 100644 index 0000000000..a02086f296 --- /dev/null +++ b/tests/generichotplugdata/generichotplug-watchdog.xml @@ -0,0 +1 @@ +<watchdog model='i6300esb'/> -- 2.35.1

For testing hypervisor independent device detach / attach / update functions, currently only detaching included. Signed-off-by: Luke Yue <lukedyue@gmail.com> --- The test would show error messages with expected to fail tests even with VIR_TEST_DEBUG=0, really don't know what I missed to make it quiet :( I would really appreciate it if anyone could tell me what I should do, thanks. --- tests/generichotplugtest.c | 178 +++++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 2 files changed, 179 insertions(+) create mode 100644 tests/generichotplugtest.c diff --git a/tests/generichotplugtest.c b/tests/generichotplugtest.c new file mode 100644 index 0000000000..443fc907d3 --- /dev/null +++ b/tests/generichotplugtest.c @@ -0,0 +1,178 @@ +#include <config.h> + +#include "internal.h" +#include "testutils.h" + +enum { + ATTACH, + DETACH, + UPDATE +}; + +#define VIR_FROM_THIS VIR_FROM_NONE + +struct genericHotplugTestData { + const char *device_filename; + const char *device_alias; + bool fail; + bool alias; + bool keep; + int action; + unsigned int flags; + virDomainPtr dom; +}; + +static int +testGenericHotplug(const void *data) +{ + int ret = 0; + g_autofree char *domain_xml = g_strdup_printf("test://%s/../examples/xml/test/testnode.xml", + abs_srcdir); + struct genericHotplugTestData *test = (struct genericHotplugTestData *) data; + g_autofree char *device_filename = NULL; + g_autofree char *device_alias = NULL; + g_autofree char *device_xml = NULL; + bool fail = test->fail; + bool alias = test->alias; + unsigned int flags = test->flags; + virConnectPtr conn = virConnectOpen(domain_xml); + virDomainPtr dom = NULL; + + if (!test->dom) { + dom = virDomainLookupByName(conn, "fc5"); + test->dom = dom; + } + + if (alias) { + device_alias = g_strdup_printf("%s", test->device_alias); + } else { + device_filename = g_strdup_printf("%s/generichotplugdata/generichotplug-%s.xml", + abs_srcdir, test->device_filename); + + if (virTestLoadFile(device_filename, &device_xml) < 0) + return -1; + } + + switch (test->action) { + case ATTACH: + ret = virDomainAttachDeviceFlags(test->dom, device_xml, flags); + break; + + case DETACH: + if (alias) { + ret = virDomainDetachDeviceAlias(test->dom, device_alias, flags); + } else { + ret = virDomainDetachDeviceFlags(test->dom, device_xml, flags); + } + break; + + case UPDATE: + ret = virDomainUpdateDeviceFlags(test->dom, device_xml, flags); + break; + } + + if (!test->keep) { + virDomainDestroy(test->dom); + virDomainFree(test->dom); + test->dom = NULL; + } else { + test->dom = dom; + } + virConnectClose(conn); + + return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1; +} + +static int +mymain(void) +{ + int ret = 0; + struct genericHotplugTestData data = {0}; + unsigned int test_flags = VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG; + +#define DO_TEST(ACTION, dev, dev_alias, alias_, fail_, keep_, flags_) \ + do { \ + const char *name = (alias_) ? \ + "Generic " #ACTION " alias " dev_alias : \ + "Generic " #ACTION " " dev; \ + data.action = ACTION; \ + data.device_filename = dev; \ + data.device_alias = dev_alias; \ + data.alias = alias_; \ + data.fail = fail_; \ + data.flags = flags_; \ + data.keep = keep_; \ + if (virTestRun(name, testGenericHotplug, &data) < 0) \ + ret = -1; \ + } while (0) + +#define DO_TEST_DETACH(dev, dev_alias, alias, fail, keep, flags) \ + DO_TEST(DETACH, dev, dev_alias, alias, fail, keep, flags) + + /* Every detach test is followed by a repeated one that is expected + to fail, cause the previous one should detach the device successfully */ + DO_TEST_DETACH("controller", "", false, false, true, test_flags); + DO_TEST_DETACH("controller", "", false, true, false, test_flags); + + DO_TEST_DETACH("disk-cdrom", "", false, false, true, test_flags); + DO_TEST_DETACH("disk-cdrom", "", false, true, false, test_flags); + + DO_TEST_DETACH("filesystem", "", false, false, true, test_flags); + DO_TEST_DETACH("filesystem", "", false, true, false, test_flags); + + DO_TEST_DETACH("hostdev", "", false, false, true, test_flags); + DO_TEST_DETACH("hostdev", "", false, true, false, test_flags); + + DO_TEST_DETACH("input", "", false, false, true, test_flags); + DO_TEST_DETACH("input", "", false, true, false, test_flags); + + DO_TEST_DETACH("interface", "", false, false, true, test_flags); + DO_TEST_DETACH("interface", "", false, true, false, test_flags); + + DO_TEST_DETACH("lease", "", false, false, true, test_flags); + DO_TEST_DETACH("lease", "", false, true, false, test_flags); + + DO_TEST_DETACH("memory", "", false, false, true, test_flags); + DO_TEST_DETACH("memory", "", false, true, false, test_flags); + + DO_TEST_DETACH("rng", "", false, false, true, test_flags); + DO_TEST_DETACH("rng", "", false, true, false, test_flags); + + DO_TEST_DETACH("shmem", "", false, false, true, test_flags); + DO_TEST_DETACH("shmem", "", false, true, false, test_flags); + + DO_TEST_DETACH("sound", "", false, false, true, test_flags); + DO_TEST_DETACH("sound", "", false, true, false, test_flags); + + DO_TEST_DETACH("tpm", "", false, false, true, test_flags); + DO_TEST_DETACH("tpm", "", false, true, false, test_flags); + + DO_TEST_DETACH("vsock", "", false, false, true, test_flags); + DO_TEST_DETACH("vsock", "", false, true, false, test_flags); + + DO_TEST_DETACH("watchdog", "", false, false, true, test_flags); + DO_TEST_DETACH("watchdog", "", false, true, false, test_flags); + + DO_TEST_DETACH("disk-cdrom", "", false, false, true, test_flags); + DO_TEST_DETACH("", "ua-testCD", true, true, false, test_flags); + + DO_TEST_DETACH("", "ua-testCD", true, false, true, test_flags); + DO_TEST_DETACH("", "ua-testCD", true, true, false, test_flags); + + /* Memballoon device shouldn't be hotpluggable */ + DO_TEST_DETACH("memballoon", "", false, true, false, test_flags); + + DO_TEST_DETACH("memballoon", "", false, false, true, + VIR_DOMAIN_AFFECT_CONFIG); + DO_TEST_DETACH("memballoon", "", false, true, false, + VIR_DOMAIN_AFFECT_CONFIG); + + if (data.dom) { + virDomainDestroy(data.dom); + virDomainFree(data.dom); + } + + return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIR_TEST_MAIN(mymain) diff --git a/tests/meson.build b/tests/meson.build index 8f92f2033f..077457d15c 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -289,6 +289,7 @@ tests += [ { 'name': 'cputest', 'link_with': cputest_link_with, 'link_whole': cputest_link_whole }, { 'name': 'domaincapstest', 'link_with': domaincapstest_link_with, 'link_whole': domaincapstest_link_whole }, { 'name': 'domainconftest' }, + { 'name': 'generichotplugtest' }, { 'name': 'genericxml2xmltest' }, { 'name': 'interfacexml2xmltest' }, { 'name': 'metadatatest' }, -- 2.35.1

On Mon, 2022-02-07 at 15:38 +0800, Luke Yue wrote:
diff to v4: - Rebase to current master
diff to v3: - Add virDomainDeviceDefOperationsCallbacks to xmlopt for de- duplicating purpose - Add virDomainDeviceTypeFlags for de-duplicating purpose - Remove the memballoon helper function - Squash test_driver commits - Move test device xmls to generichotplugdata - Reimplement tests with internal APIs
link to v4: https://listman.redhat.com/archives/libvir-list/2021-December/msg00108.html link to v3: https://listman.redhat.com/archives/libvir-list/2021-November/msg00288.html link to CI: https://gitlab.com/lukedyue/libvirt/-/pipelines/464756840
Luke Yue (8): conf: Introduce virDomainInputDefRemove and fix memory leak conf: Introduce virDomainDeviceDefOperationsCallbacks to xmlopt conf: Add virDomainDeviceTypeFlags and use it in various drivers conf: Add tpm helpers for future use domain_driver: extract DetachXXXDeviceConfig related functions and use them test_driver: Implement virDomainDetachDeviceFlags examples: xml: test: add xml for testing devices related APIs tests: Add generichotplugtest
examples/xml/test/meson.build | 1 + examples/xml/test/testdomfc5.xml | 54 ++ examples/xml/test/testnodeinline.xml | 54 ++ src/bhyve/bhyve_domain.c | 2 +- src/ch/ch_conf.c | 2 +- src/conf/domain_conf.c | 572 +++++++++++++++++- src/conf/domain_conf.h | 135 ++++- src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 3 +- src/libvirt_private.syms | 21 + src/libxl/libxl_conf.c | 3 +- src/libxl/libxl_domain.c | 8 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 73 +-- src/lxc/lxc_conf.c | 3 +- src/lxc/lxc_domain.c | 7 + src/lxc/lxc_domain.h | 1 + src/lxc/lxc_driver.c | 62 +- src/openvz/openvz_conf.c | 2 +- src/qemu/qemu_conf.c | 3 +- src/qemu/qemu_domain.c | 39 ++ src/qemu/qemu_domain.h | 6 + src/qemu/qemu_driver.c | 206 +------ src/qemu/qemu_process.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/test/test_driver.c | 197 +++++- src/vbox/vbox_common.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/vz/vz_driver.c | 2 +- tests/bhyveargv2xmltest.c | 2 +- .../generichotplug-controller.xml | 1 + .../generichotplug-disk-cdrom.xml | 5 + .../generichotplug-filesystem.xml | 6 + .../generichotplug-hostdev.xml | 5 + .../generichotplug-input.xml | 1 + .../generichotplug-interface.xml | 6 + .../generichotplug-lease.xml | 5 + .../generichotplug-memballoon.xml | 3 + .../generichotplug-memory.xml | 6 + .../generichotplugdata/generichotplug-rng.xml | 4 + .../generichotplug-shmem.xml | 4 + .../generichotplug-sound.xml | 3 + .../generichotplugdata/generichotplug-tpm.xml | 5 + .../generichotplug-vsock.xml | 3 + .../generichotplug-watchdog.xml | 1 + tests/generichotplugtest.c | 178 ++++++ tests/meson.build | 1 + tests/testutils.c | 2 +- 49 files changed, 1378 insertions(+), 332 deletions(-) create mode 100644 tests/generichotplugdata/generichotplug- controller.xml create mode 100644 tests/generichotplugdata/generichotplug-disk- cdrom.xml create mode 100644 tests/generichotplugdata/generichotplug- filesystem.xml create mode 100644 tests/generichotplugdata/generichotplug- hostdev.xml create mode 100644 tests/generichotplugdata/generichotplug-input.xml create mode 100644 tests/generichotplugdata/generichotplug- interface.xml create mode 100644 tests/generichotplugdata/generichotplug-lease.xml create mode 100644 tests/generichotplugdata/generichotplug- memballoon.xml create mode 100644 tests/generichotplugdata/generichotplug- memory.xml create mode 100644 tests/generichotplugdata/generichotplug-rng.xml create mode 100644 tests/generichotplugdata/generichotplug-shmem.xml create mode 100644 tests/generichotplugdata/generichotplug-sound.xml create mode 100644 tests/generichotplugdata/generichotplug-tpm.xml create mode 100644 tests/generichotplugdata/generichotplug-vsock.xml create mode 100644 tests/generichotplugdata/generichotplug- watchdog.xml create mode 100644 tests/generichotplugtest.c
Ping =)
participants (1)
-
Luke Yue