[libvirt] [RFC PATCH] hostdev: add support for "managed='detach'"

Laine Stump laine at laine.org
Mon Mar 14 19:41:48 UTC 2016


Suggested by Alex Williamson.

If you plan to assign a GPU to a virtual machine, but that GPU happens
to be the host system console, you likely want it to start out using
the host driver (so that boot messages/etc will be displayed), then
later have the host driver replaced with vfio-pci for assignment to
the virtual machine.

However, in at least some cases (e.g. Intel i915) once the device has
been detached from the host driver and attached to vfio-pci, attempts
to reattach to the host driver only lead to "grief" (ask Alex for
details). This means that simply using "managed='yes'" in libvirt
won't work.

And if you set "managed='no'" in libvirt then either you have to
manually run virsh nodedev-detach prior to the first start of the
guest, or you have to have a management application intelligent enough
to know that it should detach from the host driver, but never reattach
to it.

This patch makes it simple/automatic to deal with such a case - it
adds a third "managed" mode for assigned PCI devices, called
"detach". It will detach ("unbind" in driver parlance) the device from
the host driver prior to assigning it to the guest, but when the guest
is finished with the device, will leave it bound to vfio-pci. This
allows re-using the device for another guest, without requiring
initial out-of-band intervention to unbind the host driver.
---

I'm sending this with the "RFC" tag because I'm concerned it might be
considered "feature creep" by some (although I think it makes at least
as much sense as "managed='yes'") and also because, even once (if) it
is ACKed, I wouldn't want to push it until abologna is finished
hacking around with the driver bind/unbind code - he has enough grief
to deal with without me causing a bunch of merge conflicts :-)


 docs/formatdomain.html.in                          | 29 ++++++++++++-----
 docs/schemas/basictypes.rng                        |  8 +++++
 docs/schemas/domaincommon.rng                      |  4 +--
 docs/schemas/network.rng                           |  2 +-
 src/conf/domain_conf.c                             | 21 +++++++-----
 src/conf/domain_conf.h                             |  2 +-
 src/conf/network_conf.c                            | 18 +++++------
 src/conf/network_conf.h                            |  5 +--
 src/libvirt_private.syms                           |  2 ++
 src/network/bridge_driver.c                        |  2 +-
 src/qemu/qemu_parse_command.c                      |  4 +--
 src/util/virhostdev.c                              | 10 +++---
 src/util/virpci.c                                  | 14 +++++---
 src/util/virpci.h                                  | 14 ++++++--
 src/xenconfig/xen_common.c                         |  3 +-
 src/xenconfig/xen_sxpr.c                           |  9 +++---
 tests/networkxml2xmlin/hostdev-managed-detach.xml  | 10 ++++++
 tests/networkxml2xmlout/hostdev-managed-detach.xml | 10 ++++++
 tests/networkxml2xmltest.c                         |  1 +
 .../qemuxml2argv-hostdev-managed-detach.args       | 22 +++++++++++++
 .../qemuxml2argv-hostdev-managed-detach.xml        | 30 ++++++++++++++++++
 tests/qemuxml2argvtest.c                           |  3 ++
 .../qemuxml2xmlout-hostdev-managed-detach.xml      | 37 ++++++++++++++++++++++
 tests/qemuxml2xmltest.c                            |  1 +
 tests/virhostdevtest.c                             |  8 ++---
 25 files changed, 215 insertions(+), 54 deletions(-)
 create mode 100644 tests/networkxml2xmlin/hostdev-managed-detach.xml
 create mode 100644 tests/networkxml2xmlout/hostdev-managed-detach.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-managed-detach.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 41f2488..a732c1c 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3323,15 +3323,28 @@
             hot-unplugged.
           </dd>
           <dt>pci</dt>
-          <dd>For PCI devices, when <code>managed</code> is "yes" it is
-            detached from the host before being passed on to the guest
-            and reattached to the host after the guest exits. If
+          <dd>For PCI devices, when <code>managed</code> is "yes" it
+            is detached from the host driver (and attached to the
+            appropriate driver for the planned type of device
+            assignment, e.g. vfio-pci for VFIO, pci-stub for legacy
+            kvm, or pciback for Xen device passthrough) before being
+            passed to the guest, and reattached to the host driver
+            after the guest exits. If <code>managed</code> is
+            "detach", then the device is detached from the host driver
+            before passing to the guest, but is left attached to
+            vfio-pci or pci-stub when the guest exits. If
             <code>managed</code> is omitted or "no", the user is
-            responsible to call <code>virNodeDeviceDetachFlags</code>
-            (or <code>virsh nodedev-detach</code> before starting the guest
-            or hot-plugging the device and <code>virNodeDeviceReAttach</code>
-            (or <code>virsh nodedev-reattach</code>) after hot-unplug or
-            stopping the guest.
+            responsible for assuring that the device is attached to
+            the proper driver for the desired device assignment mode
+            before starting the guest or hot-plugging the device. This
+            can be done in the libvirt API with
+            <code>virNodeDeviceDetachFlags</code> (or by running
+            <code>virsh nodedev-detach</code>). Likewise, once the
+            guest is finished using the device, it will be up to the
+            user to re-attach it to the host driver (if that is
+            desired), or example by using
+            libvirt's <code>virNodeDeviceReAttach</code> API or
+            running <code>virsh nodedev-reattach</code>.
           </dd>
           <dt>scsi</dt>
           <dd>For SCSI devices, user is responsible to make sure the device
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index a83063a..50ba9c7 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -88,6 +88,14 @@
     </optional>
   </define>
 
+  <define name="virPCIManagedMode">
+    <choice>
+      <value>no</value>
+      <value>yes</value>
+      <value>detach</value>
+    </choice>
+  </define>
+
   <!-- a 6 byte MAC address in ASCII-hex format, eg "12:34:56:78:9A:BC" -->
   <!-- The lowest bit of the 1st byte is the "multicast" bit. a         -->
   <!-- uniMacAddr requires that bit to be 0, and a multiMacAddr         -->
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 8c6287d..3701f4f 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2241,7 +2241,7 @@
           </attribute>
           <optional>
             <attribute name="managed">
-              <ref name="virYesNo"/>
+              <ref name="virPCIManagedMode"/>
             </attribute>
           </optional>
           <interleave>
@@ -3756,7 +3756,7 @@
     </optional>
     <optional>
       <attribute name="managed">
-        <ref name="virYesNo"/>
+        <ref name="virPCIManagedMode"/>
       </attribute>
     </optional>
     <choice>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 4edb6eb..f5e049b 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -112,7 +112,7 @@
 
             <optional>
               <attribute name="managed">
-                <ref name="virYesNo"/>
+                <ref name="virPCIManagedMode"/>
               </attribute>
             </optional>
             <interleave>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7d68096..2332b69 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -39,6 +39,7 @@
 #include "viruuid.h"
 #include "virbuffer.h"
 #include "virlog.h"
+#include "virpci.h"
 #include "nwfilter_conf.h"
 #include "storage_conf.h"
 #include "virstoragefile.h"
@@ -5599,9 +5600,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
      * element that might be (pure hostdev, or higher level device
      * (e.g. <interface>) with type='hostdev')
      */
-    if ((managed = virXMLPropString(node, "managed")) != NULL) {
-        if (STREQ(managed, "yes"))
-            def->managed = true;
+    if ((managed = virXMLPropString(node, "managed")) &&
+        (def->managed = virPCIManagedModeTypeFromString(managed)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown managed mode '%s'"), managed);
+        goto error;
     }
 
     sgio = virXMLPropString(node, "sgio");
@@ -19808,8 +19811,9 @@ virDomainActualNetDefFormat(virBufferPtr buf,
     virBufferAsprintf(buf, "<actual type='%s'", typeStr);
     if (type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
         virDomainHostdevDefPtr hostdef = virDomainNetGetActualHostdev(def);
-        if  (hostdef && hostdef->managed)
-            virBufferAddLit(buf, " managed='yes'");
+        if  (hostdef && (hostdef->managed != VIR_PCI_MANAGED_NO))
+            virBufferAsprintf(buf, " managed='%s'",
+                              virPCIManagedModeTypeToString(hostdef->managed));
     }
     if (def->trustGuestRxFilters)
         virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
@@ -19979,8 +19983,9 @@ virDomainNetDefFormat(virBufferPtr buf,
     }
 
     virBufferAsprintf(buf, "<interface type='%s'", typeStr);
-    if (hostdef && hostdef->managed)
-        virBufferAddLit(buf, " managed='yes'");
+    if  (hostdef && (hostdef->managed != VIR_PCI_MANAGED_NO))
+        virBufferAsprintf(buf, " managed='%s'",
+                          virPCIManagedModeTypeToString(hostdef->managed));
     if (def->trustGuestRxFilters)
         virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                           virTristateBoolTypeToString(def->trustGuestRxFilters));
@@ -21430,7 +21435,7 @@ virDomainHostdevDefFormat(virBufferPtr buf,
                       mode, type);
     if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
         virBufferAsprintf(buf, " managed='%s'",
-                          def->managed ? "yes" : "no");
+                          virPCIManagedModeTypeToString(def->managed));
 
         if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
             scsisrc->sgio)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 85c4f55..42c7d36 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -543,7 +543,7 @@ struct _virDomainHostdevDef {
     virDomainDeviceDef parent; /* higher level Def containing this */
     int mode; /* enum virDomainHostdevMode */
     int startupPolicy; /* enum virDomainStartupPolicy */
-    bool managed;
+    int managed; /* enum virPCIManagedMode */
     bool missing;
     bool readonly;
     bool shareable;
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 4fb2e2a..a40f3e0 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1,7 +1,7 @@
 /*
  * network_conf.c: network XML handling
  *
- * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006-2016 Red Hat, Inc.
  * Copyright (C) 2006-2008 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -43,6 +43,7 @@
 #include "virbuffer.h"
 #include "c-ctype.h"
 #include "virfile.h"
+#include "virpci.h"
 #include "virstring.h"
 
 #define VIR_FROM_THIS VIR_FROM_NETWORK
@@ -1825,10 +1826,11 @@ virNetworkForwardDefParseXML(const char *networkName,
         VIR_FREE(type);
     }
 
-    forwardManaged = virXPathString("string(./@managed)", ctxt);
-    if (forwardManaged != NULL &&
-        STRCASEEQ(forwardManaged, "yes")) {
-        def->managed = true;
+    if ((forwardManaged = virXPathString("string(./@managed)", ctxt)) &&
+        (def->managed = virPCIManagedModeTypeFromString(forwardManaged)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown managed mode '%s'"), forwardManaged);
+        goto cleanup;
     }
 
     forwardDriverName = virXPathString("string(./driver/@name)", ctxt);
@@ -2723,10 +2725,8 @@ virNetworkDefFormatBuf(virBufferPtr buf,
         virBufferEscapeString(buf, " dev='%s'", dev);
         virBufferAsprintf(buf, " mode='%s'", mode);
         if (def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
-            if (def->forward.managed)
-                virBufferAddLit(buf, " managed='yes'");
-            else
-                virBufferAddLit(buf, " managed='no'");
+            virBufferAsprintf(buf, " managed='%s'",
+                              virPCIManagedModeTypeToString(def->forward.managed));
         }
         shortforward = !(def->forward.nifs || def->forward.npfs
                          || VIR_SOCKET_ADDR_VALID(&def->forward.addr.start)
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index b72257b..3b86781 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -1,7 +1,7 @@
 /*
  * network_conf.h: network XML handling
  *
- * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006-2016 Red Hat, Inc.
  * Copyright (C) 2006-2008 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -187,7 +187,8 @@ typedef struct _virNetworkForwardDef virNetworkForwardDef;
 typedef virNetworkForwardDef *virNetworkForwardDefPtr;
 struct _virNetworkForwardDef {
     int type;     /* One of virNetworkForwardType constants */
-    bool managed;  /* managed attribute for hostdev mode */
+    int managed;  /* managed attribute for hostdev mode */
+                  /* enum virPCIManagedMode */
     int driverName; /* enum virNetworkForwardDriverNameType */
 
     /* If there are multiple forward devices (i.e. a pool of
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 55c3047..3dd00ec 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2010,6 +2010,8 @@ virPCIGetVirtualFunctionIndex;
 virPCIGetVirtualFunctionInfo;
 virPCIGetVirtualFunctions;
 virPCIIsVirtualFunction;
+virPCIManagedModeTypeFromString;
+virPCIManagedModeTypeToString;
 virPCIStubDriverTypeFromString;
 virPCIStubDriverTypeToString;
 
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 01c2ed6..bd1f57c 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -4085,7 +4085,7 @@ networkAllocateActualDevice(virDomainDefPtr dom,
         iface->data.network.actual->data.hostdev.def.parent.data.net = iface;
         iface->data.network.actual->data.hostdev.def.info = &iface->info;
         iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
-        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
+        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed;
         iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
         iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
 
diff --git a/src/qemu/qemu_parse_command.c b/src/qemu/qemu_parse_command.c
index 60e3d69..060bf66 100644
--- a/src/qemu/qemu_parse_command.c
+++ b/src/qemu/qemu_parse_command.c
@@ -1192,7 +1192,7 @@ qemuParseCommandLinePCI(const char *val)
     }
 
     def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
-    def->managed = true;
+    def->managed = VIR_PCI_MANAGED_YES;
     def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
     def->source.subsys.u.pci.addr.bus = bus;
     def->source.subsys.u.pci.addr.slot = slot;
@@ -1255,7 +1255,7 @@ qemuParseCommandLineUSB(const char *val)
     }
 
     def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
-    def->managed = false;
+    def->managed = VIR_PCI_MANAGED_NO;
     def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
     if (*end == '.') {
         usbsrc->bus = first;
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 098207e..4baf884 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -1,6 +1,6 @@
 /* virhostdev.c: hostdev management
  *
- * Copyright (C) 2006-2007, 2009-2015 Red Hat, Inc.
+ * Copyright (C) 2006-2007, 2009-2016 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
  *
@@ -592,7 +592,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
     for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
         virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
 
-        if (virPCIDeviceGetManaged(dev)) {
+        if (virPCIDeviceGetManaged(dev) != VIR_PCI_MANAGED_NO) {
             VIR_DEBUG("Detaching managed PCI device %s",
                       virPCIDeviceGetName(dev));
             if (virPCIDeviceDetach(dev,
@@ -726,7 +726,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
     for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
         virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
 
-        if (virPCIDeviceGetManaged(dev)) {
+        if (virPCIDeviceGetManaged(dev) == VIR_PCI_MANAGED_YES) {
             VIR_DEBUG("Reattaching managed PCI device %s",
                       virPCIDeviceGetName(dev));
             ignore_value(virPCIDeviceReattach(dev,
@@ -756,7 +756,7 @@ virHostdevReattachPCIDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr)
     /* If the device is not managed and was attached to guest
      * successfully, it must have been inactive.
      */
-    if (!virPCIDeviceGetManaged(dev)) {
+    if (virPCIDeviceGetManaged(dev) != VIR_PCI_MANAGED_YES) {
         VIR_DEBUG("Adding unmanaged PCI device %s to inactive list",
                   virPCIDeviceGetName(dev));
         if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, dev) < 0)
@@ -1312,7 +1312,7 @@ virHostdevPrepareSCSIHostDevices(virDomainHostdevDefPtr hostdev,
     virSCSIDevicePtr scsi;
     int ret = -1;
 
-    if (hostdev->managed) {
+    if (hostdev->managed != VIR_PCI_MANAGED_NO) {
         virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("SCSI host device doesn't support managed mode"));
         goto cleanup;
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 1854318..7164824 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -1,7 +1,7 @@
 /*
  * virpci.c: helper APIs for managing host PCI devices
  *
- * Copyright (C) 2009-2015 Red Hat, Inc.
+ * Copyright (C) 2009-2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -62,6 +62,11 @@ VIR_ENUM_IMPL(virPCIStubDriver, VIR_PCI_STUB_DRIVER_LAST,
               "vfio-pci", /* VFIO */
 );
 
+VIR_ENUM_IMPL(virPCIManagedMode, VIR_PCI_MANAGED_LAST,
+              "no",
+              "yes",
+              "detach");
+
 struct _virPCIDevice {
     virPCIDeviceAddress address;
 
@@ -77,7 +82,7 @@ struct _virPCIDevice {
     unsigned int  pci_pm_cap_pos;
     bool          has_flr;
     bool          has_pm_reset;
-    bool          managed;
+    virPCIManagedMode managed;
 
     virPCIStubDriver stubDriver;
 
@@ -1702,12 +1707,13 @@ virPCIDeviceGetName(virPCIDevicePtr dev)
     return dev->name;
 }
 
-void virPCIDeviceSetManaged(virPCIDevicePtr dev, bool managed)
+void virPCIDeviceSetManaged(virPCIDevicePtr dev,
+                            virPCIManagedMode managed)
 {
     dev->managed = managed;
 }
 
-bool
+virPCIManagedMode
 virPCIDeviceGetManaged(virPCIDevicePtr dev)
 {
     return dev->managed;
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 55329c8..1969e29 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -53,6 +53,16 @@ typedef enum {
 VIR_ENUM_DECL(virPCIStubDriver);
 
 typedef enum {
+   VIR_PCI_MANAGED_NO,
+   VIR_PCI_MANAGED_YES,
+   VIR_PCI_MANAGED_DETACH,
+
+   VIR_PCI_MANAGED_LAST
+} virPCIManagedMode;
+
+VIR_ENUM_DECL(virPCIManagedMode);
+
+typedef enum {
     VIR_PCIE_LINK_SPEED_NA = 0,
     VIR_PCIE_LINK_SPEED_25,
     VIR_PCIE_LINK_SPEED_5,
@@ -98,8 +108,8 @@ int virPCIDeviceReset(virPCIDevicePtr dev,
                       virPCIDeviceListPtr inactiveDevs);
 
 void virPCIDeviceSetManaged(virPCIDevice *dev,
-                            bool managed);
-bool virPCIDeviceGetManaged(virPCIDevice *dev);
+                            virPCIManagedMode managed);
+virPCIManagedMode virPCIDeviceGetManaged(virPCIDevice *dev);
 void virPCIDeviceSetStubDriver(virPCIDevicePtr dev,
                                virPCIStubDriver driver);
 virPCIStubDriver virPCIDeviceGetStubDriver(virPCIDevicePtr dev);
diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c
index 828c8e9..db4745c 100644
--- a/src/xenconfig/xen_common.c
+++ b/src/xenconfig/xen_common.c
@@ -32,6 +32,7 @@
 #include "virerror.h"
 #include "virconf.h"
 #include "viralloc.h"
+#include "virpci.h"
 #include "viruuid.h"
 #include "count-one-bits.h"
 #include "xenxs_private.h"
@@ -461,7 +462,7 @@ xenParsePCI(virConfPtr conf, virDomainDefPtr def)
             if (!(hostdev = virDomainHostdevDefAlloc()))
                return -1;
 
-            hostdev->managed = false;
+            hostdev->managed = VIR_PCI_MANAGED_NO;
             hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
             hostdev->source.subsys.u.pci.addr.domain = domainID;
             hostdev->source.subsys.u.pci.addr.bus = busID;
diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c
index fdfec2b..51b32a4 100644
--- a/src/xenconfig/xen_sxpr.c
+++ b/src/xenconfig/xen_sxpr.c
@@ -1,7 +1,7 @@
 /*
  * xen_sxpr.c: Xen SEXPR parsing functions
  *
- * Copyright (C) 2010-2014 Red Hat, Inc.
+ * Copyright (C) 2010-2014, 2016 Red Hat, Inc.
  * Copyright (C) 2011 Univention GmbH
  * Copyright (C) 2005 Anthony Liguori <aliguori at us.ibm.com>
  *
@@ -32,6 +32,7 @@
 #include "virerror.h"
 #include "virconf.h"
 #include "viralloc.h"
+#include "virpci.h"
 #include "verify.h"
 #include "viruuid.h"
 #include "virlog.h"
@@ -1114,7 +1115,7 @@ xenParseSxprPCI(virDomainDefPtr def,
            goto error;
 
         dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
-        dev->managed = false;
+        dev->managed = VIR_PCI_MANAGED_NO;
         dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
         dev->source.subsys.u.pci.addr.domain = domainID;
         dev->source.subsys.u.pci.addr.bus = busID;
@@ -2002,7 +2003,7 @@ xenFormatSxprOnePCI(virDomainHostdevDefPtr def,
                     virBufferPtr buf,
                     int detach)
 {
-    if (def->managed) {
+    if (def->managed != VIR_PCI_MANAGED_NO) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("managed PCI devices not supported with XenD"));
         return -1;
@@ -2062,7 +2063,7 @@ xenFormatSxprAllPCI(virDomainDefPtr def,
     for (i = 0; i < def->nhostdevs; i++) {
         if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
             def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
-            if (def->hostdevs[i]->managed) {
+            if (def->hostdevs[i]->managed != VIR_PCI_MANAGED_NO) {
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                                _("managed PCI devices not supported with XenD"));
                 return -1;
diff --git a/tests/networkxml2xmlin/hostdev-managed-detach.xml b/tests/networkxml2xmlin/hostdev-managed-detach.xml
new file mode 100644
index 0000000..3a5fac4
--- /dev/null
+++ b/tests/networkxml2xmlin/hostdev-managed-detach.xml
@@ -0,0 +1,10 @@
+<network>
+  <name>hostdev</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward mode='hostdev' managed='detach'>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x2'/>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x3'/>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x4'/>
+  </forward>
+</network>
diff --git a/tests/networkxml2xmlout/hostdev-managed-detach.xml b/tests/networkxml2xmlout/hostdev-managed-detach.xml
new file mode 100644
index 0000000..3a5fac4
--- /dev/null
+++ b/tests/networkxml2xmlout/hostdev-managed-detach.xml
@@ -0,0 +1,10 @@
+<network>
+  <name>hostdev</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward mode='hostdev' managed='detach'>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x2'/>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x3'/>
+    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x4'/>
+  </forward>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index 8d60aa8..ec9a47f 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -108,6 +108,7 @@ mymain(void)
     DO_TEST("openvswitch-net");
     DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE);
     DO_TEST("hostdev");
+    DO_TEST("hostdev-managed-detach");
     DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
     DO_TEST("passthrough-address-crash");
     DO_TEST("nat-network-explicit-flood");
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.args
new file mode 100644
index 0000000..9e37ed5
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.args
@@ -0,0 +1,22 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuestManagedUnbind \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-uuid c7a5fdbd-edaf-9466-926a-d65c16db1809 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuestManagedUnbi/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-device vfio-pci,host=06:12.5,id=hostdev0,bus=pci.0,addr=0x3 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.xml
new file mode 100644
index 0000000..2d12d98
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-managed-detach.xml
@@ -0,0 +1,30 @@
+<domain type='qemu'>
+  <name>QEMUGuestManagedUnbind</name>
+  <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219100</memory>
+  <currentMemory unit='KiB'>219100</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' 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</emulator>
+    <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='pci' managed='detach'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/>
+      </source>
+    </hostdev>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index e15da37..433e3a7 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1278,6 +1278,9 @@ mymain(void)
     DO_TEST_FAILURE("hostdev-vfio-multidomain",
                     QEMU_CAPS_PCIDEVICE,
                     QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_VFIO_PCI);
+    DO_TEST("hostdev-managed-detach",
+            QEMU_CAPS_PCIDEVICE, QEMU_CAPS_NODEFCONFIG,
+            QEMU_CAPS_DEVICE_VFIO_PCI);
     DO_TEST("pci-rom",
             QEMU_CAPS_PCIDEVICE, QEMU_CAPS_NODEFCONFIG,
             QEMU_CAPS_PCI_ROMBAR);
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-managed-detach.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-managed-detach.xml
new file mode 100644
index 0000000..e639e91
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-hostdev-managed-detach.xml
@@ -0,0 +1,37 @@
+<domain type='qemu'>
+  <name>QEMUGuestManagedUnbind</name>
+  <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219100</memory>
+  <currentMemory unit='KiB'>219100</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' 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</emulator>
+    <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='pci' managed='detach'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/>
+      </source>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </hostdev>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 0735677..980c468 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -484,6 +484,7 @@ mymain(void)
     DO_TEST("hostdev-usb-address");
     DO_TEST("hostdev-pci-address");
     DO_TEST("hostdev-vfio");
+    DO_TEST("hostdev-managed-detach");
     DO_TEST("pci-rom");
     DO_TEST("pci-serial-dev-chardev");
 
diff --git a/tests/virhostdevtest.c b/tests/virhostdevtest.c
index 5eb2e7e..af175ca 100644
--- a/tests/virhostdevtest.c
+++ b/tests/virhostdevtest.c
@@ -166,7 +166,7 @@ testVirHostdevPreparePCIHostdevs_unmanaged(void)
     size_t active_count, inactive_count, i;
 
     for (i = 0; i < nhostdevs; i++)
-         hostdevs[i]->managed = false;
+        hostdevs[i]->managed = VIR_PCI_MANAGED_NO;
 
     active_count = virPCIDeviceListCount(mgr->activePCIHostdevs);
     inactive_count = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
@@ -225,7 +225,7 @@ testVirHostdevReAttachPCIHostdevs_unmanaged(void)
     size_t active_count, inactive_count, i;
 
     for (i = 0; i < nhostdevs; i++) {
-        if (hostdevs[i]->managed != false) {
+        if (hostdevs[i]->managed != VIR_PCI_MANAGED_NO) {
             VIR_DEBUG("invalid test");
             return -1;
         }
@@ -259,7 +259,7 @@ testVirHostdevPreparePCIHostdevs_managed(void)
     size_t active_count, inactive_count, i;
 
     for (i = 0; i < nhostdevs; i++)
-        hostdevs[i]->managed = true;
+        hostdevs[i]->managed = VIR_PCI_MANAGED_YES;
 
     active_count = virPCIDeviceListCount(mgr->activePCIHostdevs);
     inactive_count = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
@@ -310,7 +310,7 @@ testVirHostdevReAttachPCIHostdevs_managed(void)
     size_t active_count, inactive_count, i;
 
     for (i = 0; i < nhostdevs; i++) {
-        if (hostdevs[i]->managed != true) {
+        if (hostdevs[i]->managed != VIR_PCI_MANAGED_YES) {
             VIR_DEBUG("invalid test");
             return -1;
         }
-- 
2.5.0




More information about the libvir-list mailing list