]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Implement support for hotplugging evdev input devices
authorRayhan Faizel <rayhan.faizel@gmail.com>
Wed, 15 May 2024 10:27:53 +0000 (15:57 +0530)
committerMichal Privoznik <mprivozn@redhat.com>
Thu, 16 May 2024 12:56:59 +0000 (14:56 +0200)
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.

Resolves: https://gitlab.com/libvirt/libvirt/-/issues/529
Signed-off-by: Rayhan Faizel <rayhan.faizel@gmail.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/qemu/qemu_command.c
src/qemu/qemu_command.h
src/qemu/qemu_hotplug.c

index 9859ea67a40c4ee56d4f7a29c6c21c26a90acdcd..63bfeb790ee0be02294e288975c32b7f834e6e69 100644 (file)
@@ -4367,7 +4367,7 @@ qemuBuildInputUSBDevProps(const virDomainDef *def,
 }
 
 
-static virJSONValue *
+virJSONValue *
 qemuBuildInputEvdevProps(virDomainInputDef *dev)
 {
     g_autoptr(virJSONValue) props = NULL;
index 341ec43f9a25250f9ad90f7169966a0fa7122e64..dca8877703579ba765dcbf86b35416fb5f3465e1 100644 (file)
@@ -233,6 +233,9 @@ virJSONValue *
 qemuBuildInputUSBDevProps(const virDomainDef *def,
                           virDomainInputDef *dev);
 
+virJSONValue *
+qemuBuildInputEvdevProps(virDomainInputDef *dev);
+
 virJSONValue *
 qemuBuildVsockDevProps(virDomainDef *def,
                        virDomainVsockDef *vsock,
index 3b399417809a2345b7fe105e0bbfdcd27de767a2..4739beead8811e5ed3a610fe0c1eb2a002804099 100644 (file)
@@ -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,