[PATCH 1/2] qemu: Implement support for hotplugging evdev input devices

Rayhan Faizel posted 2 patches 6 months, 1 week ago
[PATCH 1/2] qemu: Implement support for hotplugging evdev input devices
Posted by Rayhan Faizel 6 months, 1 week ago
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@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