If usb device attached to a domain is unplugged from host and
then plugged back then it will no longer be available in guest.
We are going to support this case so that device will be detached
from qemu on unplug and attached back on replug. As sometimes
this behaviour is not desirable and for backcompat too let's
add 'replug' option for usb hostdev.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
docs/formatdomain.html.in | 10 ++++-
docs/schemas/domaincommon.rng | 5 +++
src/conf/domain_conf.c | 30 ++++++++++++++
src/conf/domain_conf.h | 2 +
tests/qemuxml2argvdata/hostdev-usb-replug.xml | 36 +++++++++++++++++
.../qemuxml2xmloutdata/hostdev-usb-replug.xml | 40 +++++++++++++++++++
tests/qemuxml2xmltest.c | 1 +
7 files changed, 122 insertions(+), 2 deletions(-)
create mode 100644 tests/qemuxml2argvdata/hostdev-usb-replug.xml
create mode 100644 tests/qemuxml2xmloutdata/hostdev-usb-replug.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 500f114f41..8e1c0bf6fa 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4688,7 +4688,7 @@
<pre>
...
<devices>
- <hostdev mode='subsystem' type='usb'>
+ <hostdev mode='subsystem' type='usb'
replug='yes'>
<source startupPolicy='optional'>
<vendor id='0x1234'/>
<product id='0xbeef'/>
@@ -4787,7 +4787,13 @@
<dt><code>usb</code></dt>
<dd>USB devices are detached from the host on guest startup
and reattached after the guest exits or the device is
- hot-unplugged.
+ hot-unplugged. If optional <code>replug</code>
+ (<span class="since">since 5.8.0</span>) is
"yes" then libvirt
+ tracks USB device unplug/plug on host. On unplug the correspondent
+ QEMU device will be be deleted but device stays in libvirt config.
+ On plug the device will be added back to QEMU. This applies only
+ for USB devices with product/vendor pair specified. Default value
+ is "no".
</dd>
<dt><code>pci</code></dt>
<dd>For PCI devices, when <code>managed</code> is
"yes" it is
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index ead5a25068..caba7f4e24 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4658,6 +4658,11 @@
<attribute name="type">
<value>usb</value>
</attribute>
+ <optional>
+ <attribute name="replug">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
<element name="source">
<optional>
<ref name="startupPolicy"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6bd2d4935d..c99758d9f5 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7702,6 +7702,13 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
goto out;
}
+ if (usbsrc->replug && (!got_vendor || !got_product)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("replug is only possible if vendor/product "
+ "pair is specified"));
+ goto out;
+ }
+
ret = 0;
out:
return ret;
@@ -8155,12 +8162,14 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
virDomainHostdevSubsysSCSIVHostPtr scsihostsrc =
&def->source.subsys.u.scsi_host;
virDomainHostdevSubsysMediatedDevPtr mdevsrc = &def->source.subsys.u.mdev;
+ virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
VIR_AUTOFREE(char *) managed = NULL;
VIR_AUTOFREE(char *) sgio = NULL;
VIR_AUTOFREE(char *) rawio = NULL;
VIR_AUTOFREE(char *) backendStr = NULL;
VIR_AUTOFREE(char *) model = NULL;
VIR_AUTOFREE(char *) display = NULL;
+ VIR_AUTOFREE(char *) replug = NULL;
/* @managed can be read from the xml document - it is always an
* attribute of the toplevel element, no matter what type of
@@ -8176,6 +8185,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
rawio = virXMLPropString(node, "rawio");
model = virXMLPropString(node, "model");
display = virXMLPropString(node, "display");
+ replug = virXMLPropString(node, "replug");
/* @type is passed in from the caller rather than read from the
* xml document, because it is specified in different places for
@@ -8242,6 +8252,20 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
}
}
+ if (replug) {
+ if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("replug is only supported for usb host device"));
+ return -1;
+ }
+
+ if ((usbsrc->replug = virTristateBoolTypeFromString(replug)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown hostdev replug setting '%s'"),
rawio);
+ return -1;
+ }
+ }
+
if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV &&
def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST) {
if (model) {
@@ -27220,6 +27244,7 @@ virDomainHostdevDefFormat(virBufferPtr buf,
virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
virDomainHostdevSubsysMediatedDevPtr mdevsrc = &def->source.subsys.u.mdev;
virDomainHostdevSubsysSCSIVHostPtr scsihostsrc =
&def->source.subsys.u.scsi_host;
+ virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
const char *type;
if (!mode) {
@@ -27284,6 +27309,11 @@ virDomainHostdevDefFormat(virBufferPtr buf,
virTristateSwitchTypeToString(mdevsrc->display));
}
+ if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
+ usbsrc->replug) {
+ virBufferAsprintf(buf, " replug='%s'",
+ virTristateBoolTypeToString(usbsrc->replug));
+ }
}
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e2edca149a..da3eff242b 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -230,6 +230,8 @@ struct _virDomainHostdevSubsysUSB {
unsigned vendor;
unsigned product;
+
+ bool replug;
};
struct _virDomainHostdevSubsysPCI {
diff --git a/tests/qemuxml2argvdata/hostdev-usb-replug.xml
b/tests/qemuxml2argvdata/hostdev-usb-replug.xml
new file mode 100644
index 0000000000..9647385667
--- /dev/null
+++ b/tests/qemuxml2argvdata/hostdev-usb-replug.xml
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <hostdev mode='subsystem' type='usb' managed='no'
replug='yes'>
+ <source>
+ <vendor id='0x1234'/>
+ <product id='0xbeef'/>
+ </source>
+ </hostdev>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/hostdev-usb-replug.xml
b/tests/qemuxml2xmloutdata/hostdev-usb-replug.xml
new file mode 100644
index 0000000000..5f4e39e2c4
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/hostdev-usb-replug.xml
@@ -0,0 +1,40 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <hostdev mode='subsystem' type='usb' managed='no'
replug='yes'>
+ <source>
+ <vendor id='0x1234'/>
+ <product id='0xbeef'/>
+ </source>
+ </hostdev>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index b9364f942f..4c275a939d 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -439,6 +439,7 @@ mymain(void)
DO_TEST("channel-unix-source-path", NONE);
DO_TEST("hostdev-usb-address", NONE);
+ DO_TEST("hostdev-usb-replug", NONE);
DO_TEST("hostdev-pci-address", NONE);
DO_TEST("hostdev-pci-multifunction", NONE);
DO_TEST("hostdev-vfio", NONE);
--
2.23.0