[libvirt] [PATCH 10/16] hostdev: Maintain a driver list of active mediated devices

Erik Skultety eskultet at redhat.com
Mon Feb 6 12:19:52 UTC 2017


Keep track of the assigned mediated devices the same way we do it for
the rest of hostdevs.

Signed-off-by: Erik Skultety <eskultet at redhat.com>
---
 src/libvirt_private.syms |   1 +
 src/qemu/qemu_hostdev.c  |  22 +++++++++
 src/qemu/qemu_hostdev.h  |   4 ++
 src/util/virhostdev.c    | 126 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/util/virhostdev.h    |   9 ++++
 5 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4047945..8921a53 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1707,6 +1707,7 @@ virHostdevPCINodeDeviceDetach;
 virHostdevPCINodeDeviceReAttach;
 virHostdevPCINodeDeviceReset;
 virHostdevPrepareDomainDevices;
+virHostdevPrepareMediatedDevices;
 virHostdevPreparePCIDevices;
 virHostdevPrepareSCSIDevices;
 virHostdevPrepareSCSIVHostDevices;
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
index 7cd49e4..45b731c 100644
--- a/src/qemu/qemu_hostdev.c
+++ b/src/qemu/qemu_hostdev.c
@@ -305,6 +305,24 @@ qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
 }
 
 int
+qemuHostdevPrepareMediatedDevices(virQEMUDriverPtr driver,
+                                  const char *name,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs)
+{
+    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
+
+    if (!qemuHostdevHostSupportsPassthroughVFIO()) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("host doesn't support VFIO PCI interface"));
+        return -1;
+    }
+
+    return virHostdevPrepareMediatedDevices(hostdev_mgr, QEMU_DRIVER_NAME,
+                                            name, hostdevs, nhostdevs);
+}
+
+int
 qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
                                 virDomainDefPtr def,
                                 virQEMUCapsPtr qemuCaps,
@@ -330,6 +348,10 @@ qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
                                            def->hostdevs, def->nhostdevs) < 0)
         return -1;
 
+    if (qemuHostdevPrepareMediatedDevices(driver, def->name,
+                                          def->hostdevs, def->nhostdevs) < 0)
+        return -1;
+
     return 0;
 }
 
diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h
index 74a7d4f..9399241 100644
--- a/src/qemu/qemu_hostdev.h
+++ b/src/qemu/qemu_hostdev.h
@@ -59,6 +59,10 @@ int qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
                                        const char *name,
                                        virDomainHostdevDefPtr *hostdevs,
                                        int nhostdevs);
+int qemuHostdevPrepareMediatedDevices(virQEMUDriverPtr driver,
+                                      const char *name,
+                                      virDomainHostdevDefPtr *hostdevs,
+                                      int nhostdevs);
 int qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
                                     virDomainDefPtr def,
                                     virQEMUCapsPtr qemuCaps,
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 86ca8e0..7691eaa 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -1,6 +1,6 @@
 /* virhostdev.c: hostdev management
  *
- * Copyright (C) 2006-2007, 2009-2016 Red Hat, Inc.
+ * Copyright (C) 2006-2007, 2009-2017 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
  *
@@ -147,6 +147,7 @@ virHostdevManagerDispose(void *obj)
     virObjectUnref(hostdevMgr->activeUSBHostdevs);
     virObjectUnref(hostdevMgr->activeSCSIHostdevs);
     virObjectUnref(hostdevMgr->activeSCSIVHostHostdevs);
+    virObjectUnref(hostdevMgr->activeMediatedHostdevs);
     VIR_FREE(hostdevMgr->stateDir);
 }
 
@@ -174,6 +175,9 @@ virHostdevManagerNew(void)
     if (!(hostdevMgr->activeSCSIVHostHostdevs = virSCSIVHostDeviceListNew()))
         goto error;
 
+    if (!(hostdevMgr->activeMediatedHostdevs = virMediatedDeviceListNew()))
+        goto error;
+
     if (privileged) {
         if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0)
             goto error;
@@ -1595,6 +1599,126 @@ virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr mgr,
     return -1;
 }
 
+static int
+virHostdevMarkMediatedDevices(virHostdevManagerPtr mgr,
+                              const char *drvname,
+                              const char *domname,
+                              virMediatedDeviceListPtr list)
+{
+    size_t i, j;
+    unsigned int count;
+    virMediatedDevicePtr tmp;
+
+    virObjectLock(mgr->activeMediatedHostdevs);
+    count = virMediatedDeviceListCount(list);
+
+    for (i = 0; i < count; i++) {
+        virMediatedDevicePtr mdev = virMediatedDeviceListGet(list, i);
+        if ((tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs,
+                                             mdev))) {
+            char *tmp_drvname;
+            char *tmp_domname;
+
+            virMediatedDeviceGetUsedBy(tmp, &tmp_drvname, &tmp_domname);
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("Mediated device %s is in use by "
+                             "driver %s, domain %s"),
+                           virMediatedDeviceGetPath(tmp),
+                           tmp_drvname, tmp_domname);
+            goto error;
+        }
+
+        virMediatedDeviceSetUsedBy(mdev, drvname, domname);
+        VIR_DEBUG("Adding %s to activeMediatedHostdevs",
+                  virMediatedDeviceGetPath(mdev));
+        /*
+         * The caller is responsible to steal these mdev devices
+         * from the virMediatedDeviceList that passed in on success,
+         * perform rollback on failure.
+         */
+        if (virMediatedDeviceListAdd(mgr->activeMediatedHostdevs, mdev) < 0)
+            goto error;
+    }
+
+    virObjectUnlock(mgr->activeMediatedHostdevs);
+    return 0;
+
+ error:
+    for (j = 0; j < i; j++) {
+        tmp = virMediatedDeviceListGet(list, i);
+        virMediatedDeviceListSteal(mgr->activeMediatedHostdevs, tmp);
+    }
+    virObjectUnlock(mgr->activeMediatedHostdevs);
+    return -1;
+}
+
+int
+virHostdevPrepareMediatedDevices(virHostdevManagerPtr mgr,
+                                 const char *drv_name,
+                                 const char *dom_name,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs)
+{
+    size_t i;
+    int ret = -1;
+    virMediatedDeviceListPtr list;
+    virMediatedDevicePtr tmp;
+
+    if (!nhostdevs)
+        return 0;
+
+    /* To prevent situation where Mediated device is assigned to two domains
+     * we need to keep a list of currently assigned Mediated devices.
+     * This is done in several loops which cannot be joined into one big
+     * loop. See virHostdevPreparePCIDevices()
+     */
+    if (!(list = virMediatedDeviceListNew()))
+        goto cleanup;
+
+    /* Loop 1: build temporary list
+     */
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysMediatedDevPtr mdevsrc = &hostdev->source.subsys.u.mdev;
+        virMediatedDevicePtr mdev;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV)
+            continue;
+
+        if (!(mdev = virMediatedDeviceNew(&mdevsrc->addr, mdevsrc->uuidstr)))
+            goto cleanup;
+
+        if (virMediatedDeviceListAdd(list, mdev) < 0) {
+            virMediatedDeviceFree(mdev);
+            goto cleanup;
+        }
+    }
+
+    /* Mark devices in temporary list as used by @dom_name
+     * and add them do driver list. However, if something goes
+     * wrong, perform rollback.
+     */
+    if (virHostdevMarkMediatedDevices(mgr, drv_name, dom_name, list) < 0)
+        goto cleanup;
+
+    /* Loop 2: Temporary list was successfully merged with
+     * driver list, so steal all items to avoid freeing them
+     * in cleanup label.
+     */
+    while (virMediatedDeviceListCount(list) > 0) {
+        tmp = virMediatedDeviceListGet(list, 0);
+        virMediatedDeviceListSteal(list, tmp);
+    }
+
+    ret = 0;
+
+ cleanup:
+    virObjectUnref(list);
+    return ret;
+}
+
 void
 virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
                              const char *drv_name,
diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h
index 4c1fea3..b077089 100644
--- a/src/util/virhostdev.h
+++ b/src/util/virhostdev.h
@@ -31,6 +31,7 @@
 # include "virusb.h"
 # include "virscsi.h"
 # include "virscsivhost.h"
+# include "virmdev.h"
 # include "domain_conf.h"
 
 typedef enum {
@@ -55,6 +56,7 @@ struct _virHostdevManager {
     virUSBDeviceListPtr activeUSBHostdevs;
     virSCSIDeviceListPtr activeSCSIHostdevs;
     virSCSIVHostDeviceListPtr activeSCSIVHostHostdevs;
+    virMediatedDeviceListPtr activeMediatedHostdevs;
 };
 
 virHostdevManagerPtr virHostdevManagerGetDefault(void);
@@ -96,6 +98,13 @@ virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
                                   virDomainHostdevDefPtr *hostdevs,
                                   int nhostdevs)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int
+virHostdevPrepareMediatedDevices(virHostdevManagerPtr hostdev_mgr,
+                                 const char *drv_name,
+                                 const char *dom_name,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
 void
 virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
                              const char *drv_name,
-- 
2.10.2




More information about the libvir-list mailing list