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

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 v3: https://listman.redhat.com/archives/libvir-list/2021-November/msg00288.html link to CI: https://gitlab.com/lukedyue/libvirt/-/pipelines/421921587 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 | 204 +------ 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, 1377 insertions(+), 331 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.34.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 bdcc3dc2c1..d6f69b3ace 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16874,6 +16874,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 c0c07ea6ba..e4259bf890 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3852,6 +3852,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 7be5b51100..338207b235 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -479,6 +479,7 @@ virDomainInputBusTypeToString; virDomainInputDefFind; virDomainInputDefFree; virDomainInputDefGetPath; +virDomainInputDefRemove; virDomainInputSourceGrabToggleTypeFromString; virDomainInputSourceGrabToggleTypeToString; virDomainInputSourceGrabTypeFromString; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6333d0af36..bef2465e57 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7632,7 +7632,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.34.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 ef6f4b5ba8..a2affd5c02 100644 --- a/src/ch/ch_conf.c +++ b/src/ch/ch_conf.c @@ -115,7 +115,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 d6f69b3ace..44f1428f80 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1564,7 +1564,8 @@ virDomainXMLOptionNew(virDomainDefParserConfig *config, virDomainXMLPrivateDataCallbacks *priv, virXMLNamespace *xmlns, virDomainABIStability *abi, - virSaveCookieCallbacks *saveCookie) + virSaveCookieCallbacks *saveCookie, + virDomainDeviceDefOperationsCallbacks *deviceOps) { virDomainXMLOption *xmlopt; @@ -1589,6 +1590,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 e4259bf890..1b092b2ee5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3173,7 +3173,8 @@ virDomainXMLOption *virDomainXMLOptionNew(virDomainDefParserConfig *config, virDomainXMLPrivateDataCallbacks *priv, virXMLNamespace *xmlns, virDomainABIStability *abi, - virSaveCookieCallbacks *saveCookie); + virSaveCookieCallbacks *saveCookie, + virDomainDeviceDefOperationsCallbacks *deviceOps); virSaveCookieCallbacks * virDomainXMLOptionGetSaveCookie(virDomainXMLOption *xmlopt); @@ -3191,6 +3192,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 { @@ -3213,6 +3226,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 bafec27a88..57d2eb9ec6 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1784,7 +1784,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 f37c228139..a586454f23 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -2505,5 +2505,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 73156f15a3..c1d695e97b 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -194,7 +194,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 e2fbc28abc..b9522acd59 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -1087,5 +1087,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 7eb04e66a0..ec85b6f5a6 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1290,7 +1290,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 6b83a571b9..a2e4066158 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9238,7 +9238,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 b7ffb5e2c3..afb884e5d8 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 b6bca884f0..7febb4f5a6 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -466,7 +466,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 72f1b9c466..5d6f5e77c2 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 e6843ee745..700bb41232 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 d3540acd84..9de20d8024 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 23b7795035..01671c6cf4 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -334,7 +334,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 e460c9ecc5..3215dc981b 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -986,7 +986,7 @@ static virDomainDefParserConfig virTestGenericDomainDefParserConfig = { virDomainXMLOption *virTestGenericDomainXMLConfInit(void) { return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } -- 2.34.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 1b092b2ee5..070cb40509 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 a586454f23..4ff790ecfe 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -2505,5 +2505,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 366e3b9263..55152f9405 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -1603,3 +1603,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 c1d695e97b..31546aaeb5 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -194,7 +194,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 ec85b6f5a6..41ad081079 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1291,7 +1291,7 @@ virQEMUDriverCreateXMLConf(virQEMUDriver *driver, &virQEMUDriverDomainXMLNamespace, &virQEMUDriverDomainABIStability, &virQEMUDriverDomainSaveCookie, - NULL); + &virQEMUDriverDeviceDefOpsCallbacks); } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 2c10f185f8..050baa7c2c 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" @@ -11455,3 +11456,41 @@ qemuDomainGetVHostUserFSSocketPath(qemuDomainObjPrivate *priv, return virFileBuildPath(priv->libDir, fs->info.alias, "-fs.sock"); } + + +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; +} + + +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 f2a303d8a7..87a36b232f 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -712,6 +712,7 @@ void qemuDomainObjPrivateDataClear(qemuDomainObjPrivate *priv); extern virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks; extern virXMLNamespace virQEMUDriverDomainXMLNamespace; extern virDomainDefParserConfig virQEMUDriverDomainDefParserConfig; +extern virDomainDeviceDefOperationsCallbacks virQEMUDriverDeviceDefOpsCallbacks; extern virDomainABIStability virQEMUDriverDomainABIStability; extern virSaveCookieCallbacks virQEMUDriverDomainSaveCookie; @@ -1032,3 +1033,8 @@ qemuDomainNamePathsCleanup(virQEMUDriverConfig *cfg, char * qemuDomainGetVHostUserFSSocketPath(qemuDomainObjPrivate *priv, const virDomainFSDef *fs); + +int +qemuDomainDetachDeviceChrConfig(virDomainDef *vmdef, + virDomainDeviceDef *dev, + unsigned int flags); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 7febb4f5a6..21caa83be7 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -435,6 +435,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) { @@ -458,6 +483,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) @@ -467,7 +512,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.34.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 on default. --- 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 44f1428f80..30b06c45e5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16908,6 +16908,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 070cb40509..08b6965ef5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3905,6 +3905,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 338207b235..9b1e6a0d2a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -666,7 +666,9 @@ virDomainTimerTrackTypeFromString; virDomainTimerTrackTypeToString; virDomainTPMBackendTypeFromString; virDomainTPMBackendTypeToString; +virDomainTPMDefFind; virDomainTPMDefFree; +virDomainTPMDefRemove; virDomainTPMModelTypeFromString; virDomainTPMModelTypeToString; virDomainTPMPcrBankTypeFromString; -- 2.34.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 previous version, 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 | 205 +--------------- 6 files changed, 609 insertions(+), 314 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 30b06c45e5..8017896fd0 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -31656,3 +31656,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 08b6965ef5..12b2996538 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -4275,3 +4275,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 9b1e6a0d2a..d6f1da5e95 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 23a28dc124..dd123412ac 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3905,68 +3905,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 @@ -4199,7 +4145,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 3cdf73c69f..545fc9c9e2 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3124,58 +3124,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); } @@ -4510,7 +4465,10 @@ static int lxcDomainDetachDeviceFlags(virDomainPtr dom, if (!vmdef) goto endjob; - if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 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 bef2465e57..503b0973ab 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7468,207 +7468,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 @@ -8113,7 +7918,7 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriver *driver, goto cleanup; if (qemuDomainDetachDeviceConfig(vmdef, dev, priv->qemuCaps, - parse_flags, + flags, parse_flags, driver->xmlopt) < 0) goto cleanup; } @@ -8182,7 +7987,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.34.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 21caa83be7..6cd1e75771 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -10022,6 +10022,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 */ @@ -10119,6 +10265,9 @@ static virHypervisorDriver testHypervisorDriver = { .domainFSFreeze = testDomainFSFreeze, /* 5.7.0 */ .domainFSThaw = testDomainFSThaw, /* 5.7.0 */ .domainFSTrim = testDomainFSTrim, /* 5.7.0 */ + .domainDetachDevice = testDomainDetachDevice, /* 8.0.0 */ + .domainDetachDeviceAlias = testDomainDetachDeviceAlias, /* 8.0.0 */ + .domainDetachDeviceFlags = testDomainDetachDeviceFlags, /* 8.0.0 */ .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */ .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */ .domainGetDiskErrors = testDomainGetDiskErrors, /* 5.4.0 */ -- 2.34.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.34.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 should I 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 f75c248720..659b044984 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -288,6 +288,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.34.1
participants (1)
-
Luke Yue