Support hot-unplug for USB devices in QEMU

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
This commit is contained in:
Daniel P. Berrange 2010-03-03 15:10:36 +00:00
parent b70a1f455c
commit 8c82479d83

View File

@ -7001,9 +7001,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;
@ -7019,6 +7091,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"),
@ -7088,7 +7163,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"));