Previously hot-unplug could not be supported for USB devices
in QEMU, since usb_del required the guest visible address
which libvirt never knows. With 'device_del' command we can
now unplug based on device alias, so support that.
* src/qemu/qemu_driver.c: Use device_del to remove USB devices
---
src/qemu/qemu_driver.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0bc723d..b520ce0 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6633,9 +6633,81 @@ static int qemudDomainDetachHostPciDevice(struct qemud_driver
*driver,
return ret;
}
+static int qemudDomainDetachHostUsbDevice(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev,
+ unsigned long long qemuCmdFlags)
+{
+ virDomainHostdevDefPtr detach = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int i, ret;
+
+ for (i = 0 ; i < vm->def->nhostdevs ; i++) {
+ if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+ vm->def->hostdevs[i]->source.subsys.type !=
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
+ continue;
+
+ unsigned bus = vm->def->hostdevs[i]->source.subsys.u.usb.bus;
+ unsigned device = vm->def->hostdevs[i]->source.subsys.u.usb.device;
+
+ if (dev->data.hostdev->source.subsys.u.usb.bus == bus &&
+ dev->data.hostdev->source.subsys.u.usb.device == device) {
+ detach = vm->def->hostdevs[i];
+ break;
+ }
+ }
+
+ if (!detach) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("host usb device %03d.%03d not found"),
+ dev->data.hostdev->source.subsys.u.usb.bus,
+ dev->data.hostdev->source.subsys.u.usb.device);
+ return -1;
+ }
+
+ if (!detach->info.alias) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("device cannot be detached without a
device alias"));
+ return -1;
+ }
+
+ if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("device cannot be detached with this QEMU
version"));
+ return -1;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ return -1;
+ }
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ ret = 0;
+
+ if (vm->def->nhostdevs > 1) {
+ memmove(vm->def->hostdevs + i,
+ vm->def->hostdevs + i + 1,
+ sizeof(*vm->def->hostdevs) *
+ (vm->def->nhostdevs - (i + 1)));
+ vm->def->nhostdevs--;
+ if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
+ /* ignore, harmless */
+ }
+ } else {
+ VIR_FREE(vm->def->hostdevs);
+ vm->def->nhostdevs = 0;
+ }
+ virDomainHostdevDefFree(detach);
+
+ return ret;
+}
+
static int qemudDomainDetachHostDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
- virDomainDeviceDefPtr dev)
+ virDomainDeviceDefPtr dev,
+ unsigned long long qemuCmdFlags)
{
virDomainHostdevDefPtr hostdev = dev->data.hostdev;
int ret;
@@ -6651,6 +6723,9 @@ static int qemudDomainDetachHostDevice(struct qemud_driver *driver,
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
ret = qemudDomainDetachHostPciDevice(driver, vm, dev);
break;
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+ ret = qemudDomainDetachHostUsbDevice(driver, vm, dev, qemuCmdFlags);
+ break;
default:
qemuReportError(VIR_ERR_NO_SUPPORT,
_("hostdev subsys type '%s' not supported"),
@@ -6720,7 +6795,7 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
/* fallthrough */
}
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
- ret = qemudDomainDetachHostDevice(driver, vm, dev);
+ ret = qemudDomainDetachHostDevice(driver, vm, dev, qemuCmdFlags);
} else {
qemuReportError(VIR_ERR_NO_SUPPORT,
"%s", _("This type of device cannot be hot
unplugged"));
--
1.6.5.2