Unlike other input types, evdev is not a true device since it's backed by '-object'. We must use object-add/object-del monitor commands instead of device-add/device-del in this particular case. This patch adds support for handling live attachment and detachment of evdev type devices. Signed-off-by: Rayhan Faizel <rayhan.faizel@xxxxxxxxx> --- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_command.h | 3 ++ src/qemu/qemu_hotplug.c | 95 +++++++++++++++++++++++++++++------------ 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 9859ea67a4..63bfeb790e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4367,7 +4367,7 @@ qemuBuildInputUSBDevProps(const virDomainDef *def, } -static virJSONValue * +virJSONValue * qemuBuildInputEvdevProps(virDomainInputDef *dev) { g_autoptr(virJSONValue) props = NULL; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 341ec43f9a..dca8877703 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -233,6 +233,9 @@ virJSONValue * qemuBuildInputUSBDevProps(const virDomainDef *def, virDomainInputDef *dev); +virJSONValue * +qemuBuildInputEvdevProps(virDomainInputDef *dev); + virJSONValue * qemuBuildVsockDevProps(virDomainDef *def, virDomainVsockDef *vsock, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 3b39941780..4739beead8 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -3016,36 +3016,40 @@ qemuDomainAttachInputDevice(virDomainObj *vm, bool teardowncgroup = false; qemuAssignDeviceInputAlias(vm->def, input, -1); + if (input->type == VIR_DOMAIN_INPUT_TYPE_EVDEV) { + if (!(devprops = qemuBuildInputEvdevProps(input))) + goto cleanup; + } else { + switch ((virDomainInputBus) input->bus) { + case VIR_DOMAIN_INPUT_BUS_USB: + if (virDomainUSBAddressEnsure(priv->usbaddrs, &input->info) < 0) + return -1; - switch ((virDomainInputBus) input->bus) { - case VIR_DOMAIN_INPUT_BUS_USB: - if (virDomainUSBAddressEnsure(priv->usbaddrs, &input->info) < 0) - return -1; - - releaseaddr = true; + releaseaddr = true; - if (!(devprops = qemuBuildInputUSBDevProps(vm->def, input))) - goto cleanup; - break; + if (!(devprops = qemuBuildInputUSBDevProps(vm->def, input))) + goto cleanup; + break; - case VIR_DOMAIN_INPUT_BUS_VIRTIO: - if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev) < 0) - goto cleanup; + case VIR_DOMAIN_INPUT_BUS_VIRTIO: + if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev) < 0) + goto cleanup; - if (!(devprops = qemuBuildInputVirtioDevProps(vm->def, input, priv->qemuCaps))) - goto cleanup; - break; + if (!(devprops = qemuBuildInputVirtioDevProps(vm->def, input, priv->qemuCaps))) + goto cleanup; + break; - case VIR_DOMAIN_INPUT_BUS_DEFAULT: - case VIR_DOMAIN_INPUT_BUS_PS2: - case VIR_DOMAIN_INPUT_BUS_XEN: - case VIR_DOMAIN_INPUT_BUS_PARALLELS: - case VIR_DOMAIN_INPUT_BUS_NONE: - case VIR_DOMAIN_INPUT_BUS_LAST: - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, - _("input device on bus '%1$s' cannot be hot plugged."), - virDomainInputBusTypeToString(input->bus)); - return -1; + case VIR_DOMAIN_INPUT_BUS_DEFAULT: + case VIR_DOMAIN_INPUT_BUS_PS2: + case VIR_DOMAIN_INPUT_BUS_XEN: + case VIR_DOMAIN_INPUT_BUS_PARALLELS: + case VIR_DOMAIN_INPUT_BUS_NONE: + case VIR_DOMAIN_INPUT_BUS_LAST: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("input device on bus '%1$s' cannot be hot plugged."), + virDomainInputBusTypeToString(input->bus)); + return -1; + } } if (qemuDomainNamespaceSetupInput(vm, input, &teardowndevice) < 0) @@ -3066,9 +3070,14 @@ qemuDomainAttachInputDevice(virDomainObj *vm, if (qemuDomainAttachExtensionDevice(priv->mon, &input->info) < 0) goto exit_monitor; - if (qemuMonitorAddDeviceProps(priv->mon, &devprops) < 0) { - ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &input->info)); - goto exit_monitor; + if (input->type == VIR_DOMAIN_INPUT_TYPE_EVDEV) { + if (qemuMonitorAddObject(priv->mon, &devprops, NULL) < 0) + goto exit_monitor; + } else { + if (qemuMonitorAddDeviceProps(priv->mon, &devprops) < 0) { + ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &input->info)); + goto exit_monitor; + } } qemuDomainObjExitMonitor(vm); @@ -6093,6 +6102,29 @@ qemuDomainDetachDeviceLease(virQEMUDriver *driver, } +static int +qemuDomainDetachDeviceInputEvdev(virQEMUDriver *driver, + virDomainObj *vm, + virDomainDeviceDef *detach) +{ + int rc; + virDomainInputDef *input = detach->data.input; + qemuDomainObjPrivate *priv = vm->privateData; + + qemuDomainObjEnterMonitor(vm); + rc = qemuMonitorDelObject(priv->mon, input->info.alias, true); + qemuDomainObjExitMonitor(vm); + + if (rc < 0) + return -1; + + if (qemuDomainRemoveDevice(driver, vm, detach) < 0) + return -1; + + return 0; +} + + int qemuDomainDetachDeviceLive(virDomainObj *vm, virDomainDeviceDef *match, @@ -6176,6 +6208,13 @@ qemuDomainDetachDeviceLive(virDomainObj *vm, &detach.data.input) < 0) { return -1; } + + /* + * Input devices of type 'evdev' are regular QOM objects + * (-object instead of -device), so it must be handled differently. + */ + if (detach.data.input->type == VIR_DOMAIN_INPUT_TYPE_EVDEV) + return qemuDomainDetachDeviceInputEvdev(driver, vm, &detach); break; case VIR_DOMAIN_DEVICE_REDIRDEV: if (qemuDomainDetachPrepRedirdev(vm, match->data.redirdev, -- 2.34.1