mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-28 10:50:23 +03:00
qemu: Make save/restore with USB devices usable
Save/restore with passed through USB devices currently only works if the USB device can be found at the same USB address where it used to be before saving a domain. This makes sense in case a user explicitly configure the USB address in domain XML. However, if the device was found automatically by vendor/product identification, we should try to search for that device when restoring the domain and use any device we find as long as there is only one available. In other words, the USB device can now be removed and plugged again or the host can be rebooted between saving and restoring the domain.
This commit is contained in:
parent
28f8dfdccc
commit
bd1282d624
@ -2702,6 +2702,7 @@ virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node,
|
||||
int got_product, got_vendor;
|
||||
xmlNodePtr cur;
|
||||
char *startupPolicy = NULL;
|
||||
char *autoAddress;
|
||||
|
||||
if ((startupPolicy = virXMLPropString(node, "startupPolicy"))) {
|
||||
def->startupPolicy =
|
||||
@ -2716,6 +2717,12 @@ virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node,
|
||||
VIR_FREE(startupPolicy);
|
||||
}
|
||||
|
||||
if ((autoAddress = virXMLPropString(node, "autoAddress"))) {
|
||||
if (STREQ(autoAddress, "yes"))
|
||||
def->source.subsys.u.usb.autoAddress = true;
|
||||
VIR_FREE(autoAddress);
|
||||
}
|
||||
|
||||
/* Product can validly be 0, so we need some extra help to determine
|
||||
* if it is uninitialized*/
|
||||
got_product = 0;
|
||||
@ -12092,6 +12099,9 @@ virDomainHostdevSourceFormat(virBufferPtr buf,
|
||||
policy = virDomainStartupPolicyTypeToString(def->startupPolicy);
|
||||
virBufferAsprintf(buf, " startupPolicy='%s'", policy);
|
||||
}
|
||||
if (def->source.subsys.u.usb.autoAddress &&
|
||||
(flags & VIR_DOMAIN_XML_MIGRATABLE))
|
||||
virBufferAddLit(buf, " autoAddress='yes'");
|
||||
virBufferAddLit(buf, ">\n");
|
||||
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
|
@ -370,6 +370,8 @@ struct _virDomainHostdevSubsys {
|
||||
int type; /* enum virDomainHostdevSubsysType */
|
||||
union {
|
||||
struct {
|
||||
bool autoAddress; /* bus/device were filled automatically based
|
||||
on vedor/product */
|
||||
unsigned bus;
|
||||
unsigned device;
|
||||
|
||||
|
@ -11184,7 +11184,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
||||
} else {
|
||||
/* Easiest way to clone inactive portion of vm->def is via
|
||||
* conversion in and back out of xml. */
|
||||
if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)) ||
|
||||
if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
|
||||
!(def->dom = virDomainDefParseString(driver->caps, xml,
|
||||
QEMU_EXPECTED_VIRT_TYPES,
|
||||
VIR_DOMAIN_XML_INACTIVE)))
|
||||
@ -11735,7 +11735,8 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
|
||||
if (!(xml = qemuDomainDefFormatXML(driver,
|
||||
snap->def->dom,
|
||||
VIR_DOMAIN_XML_INACTIVE |
|
||||
VIR_DOMAIN_XML_SECURE)))
|
||||
VIR_DOMAIN_XML_SECURE |
|
||||
VIR_DOMAIN_XML_MIGRATABLE)))
|
||||
goto cleanup;
|
||||
config = virDomainDefParseString(driver->caps, xml,
|
||||
QEMU_EXPECTED_VIRT_TYPES,
|
||||
|
@ -650,15 +650,31 @@ qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
|
||||
unsigned product = hostdev->source.subsys.u.usb.product;
|
||||
unsigned bus = hostdev->source.subsys.u.usb.bus;
|
||||
unsigned device = hostdev->source.subsys.u.usb.device;
|
||||
bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
|
||||
int rc;
|
||||
|
||||
*usb = NULL;
|
||||
|
||||
if (vendor && bus) {
|
||||
rc = usbFindDevice(vendor, product, bus, device, mandatory, usb);
|
||||
if (rc < 0)
|
||||
rc = usbFindDevice(vendor, product, bus, device,
|
||||
autoAddress ? false : mandatory,
|
||||
usb);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
} else if (vendor && !bus) {
|
||||
} else if (!autoAddress) {
|
||||
goto out;
|
||||
} else {
|
||||
VIR_INFO("USB device %x:%x could not be found at previous"
|
||||
" address (bus:%u device:%u)",
|
||||
vendor, product, bus, device);
|
||||
}
|
||||
}
|
||||
|
||||
/* When vendor is specified, its USB address is either unspecified or the
|
||||
* device could not be found at the USB device where it had been
|
||||
* automatically found before.
|
||||
*/
|
||||
if (vendor) {
|
||||
usbDeviceList *devs;
|
||||
|
||||
rc = usbFindDeviceByVendor(vendor, product, mandatory, &devs);
|
||||
@ -674,15 +690,32 @@ qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
} else if (rc > 1) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("multiple USB devices for %x:%x, "
|
||||
"use <address> to specify one"),
|
||||
vendor, product);
|
||||
if (autoAddress) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Multiple USB devices for %x:%x were found,"
|
||||
" but none of them is at bus:%u device:%u"),
|
||||
vendor, product, bus, device);
|
||||
} else {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Multiple USB devices for %x:%x, "
|
||||
"use <address> to specify one"),
|
||||
vendor, product);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(*usb);
|
||||
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(*usb);
|
||||
hostdev->source.subsys.u.usb.autoAddress = true;
|
||||
|
||||
if (autoAddress) {
|
||||
VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
|
||||
" from bus:%u device:%u)",
|
||||
vendor, product,
|
||||
hostdev->source.subsys.u.usb.bus,
|
||||
hostdev->source.subsys.u.usb.device,
|
||||
bus, device);
|
||||
}
|
||||
} else if (!vendor && bus) {
|
||||
if (usbFindDeviceByBus(bus, device, mandatory, usb) < 0)
|
||||
return -1;
|
||||
|
@ -1264,7 +1264,8 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
|
||||
int hookret;
|
||||
|
||||
if (!(xml = qemuDomainDefFormatXML(driver, def,
|
||||
VIR_DOMAIN_XML_SECURE)))
|
||||
VIR_DOMAIN_XML_SECURE |
|
||||
VIR_DOMAIN_XML_MIGRATABLE)))
|
||||
goto cleanup;
|
||||
|
||||
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
|
||||
|
Loading…
x
Reference in New Issue
Block a user