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(a)gmail.com>
---
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