[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] passthrough: give XEN_DOMCTL_test_assign_device more sane semantics



So far callers of the libxc interface passed in a domain ID which was
then ignored in the hypervisor. Instead, make the hypervisor honor it
(accepting DOMID_INVALID to obtain original behavior), allowing to
query whether a device is assigned to a particular domain. Ignore the
passed in domain ID at the libxc layer instead, in order to not break
existing callers. New libxc functions would need to be added if callers
wanted to leverage the new functionality.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
TBD: Would DOMID_IO be a better fit than DOMID_INVALID here?

--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -1539,13 +1539,13 @@ int xc_get_device_group(
 
 int xc_test_assign_device(
     xc_interface *xch,
-    uint32_t domid,
+    uint32_t domid, /* ignored */
     uint32_t machine_sbdf)
 {
     DECLARE_DOMCTL;
 
     domctl.cmd = XEN_DOMCTL_test_assign_device;
-    domctl.domain = domid;
+    domctl.domain = DOMID_INVALID;
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
     domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
     domctl.u.assign_device.flags = 0;
@@ -1603,7 +1603,7 @@ int xc_assign_dt_device(
 
 int xc_test_assign_dt_device(
     xc_interface *xch,
-    uint32_t domid,
+    uint32_t domid, /* ignored */
     char *path)
 {
     int rc;
@@ -1615,7 +1615,7 @@ int xc_test_assign_dt_device(
         return -1;
 
     domctl.cmd = XEN_DOMCTL_test_assign_device;
-    domctl.domain = (domid_t)domid;
+    domctl.domain = DOMID_INVALID;
 
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
     domctl.u.assign_device.u.dt.size = size;
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -391,11 +391,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
 
     switch ( op->cmd )
     {
-    case XEN_DOMCTL_createdomain:
     case XEN_DOMCTL_test_assign_device:
+        if ( op->domain == DOMID_INVALID )
+        {
+    case XEN_DOMCTL_createdomain:
     case XEN_DOMCTL_gdbsx_guestmemio:
-        d = NULL;
-        break;
+            d = NULL;
+            break;
+        }
+        /* fall through */
     default:
         d = rcu_lock_domain_by_id(op->domain);
         if ( !d && op->cmd != XEN_DOMCTL_getdomaininfo )
--- a/xen/drivers/passthrough/device_tree.c
+++ b/xen/drivers/passthrough/device_tree.c
@@ -93,7 +93,8 @@ fail:
     return rc;
 }
 
-static bool_t iommu_dt_device_is_assigned(const struct dt_device_node *dev)
+static bool_t iommu_dt_device_is_assigned(const struct domain *d,
+                                          const struct dt_device_node *dev)
 {
     bool_t assigned = 0;
 
@@ -101,7 +102,8 @@ static bool_t iommu_dt_device_is_assigne
         return 0;
 
     spin_lock(&dtdevs_lock);
-    assigned = !list_empty(&dev->domain_list);
+    assigned = d ? dt_device_used_by(dev) == d->domain_id
+                 : !list_empty(&dev->domain_list);
     spin_unlock(&dtdevs_lock);
 
     return assigned;
@@ -209,11 +211,11 @@ int iommu_do_dt_domctl(struct xen_domctl
         if ( ret )
             break;
 
-        ret = xsm_test_assign_dtdevice(XSM_HOOK, dt_node_full_name(dev));
+        ret = xsm_test_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
         if ( ret )
             break;
 
-        if ( iommu_dt_device_is_assigned(dev) )
+        if ( iommu_dt_device_is_assigned(d, dev) )
         {
             printk(XENLOG_G_ERR "%s already assigned.\n",
                    dt_node_full_name(dev));
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -522,7 +522,7 @@ struct pci_dev *pci_get_real_pdev(int se
 }
 
 struct pci_dev *pci_get_pdev_by_domain(
-    struct domain *d, int seg, int bus, int devfn)
+    const struct domain *d, int seg, int bus, int devfn)
 {
     struct pci_seg *pseg = get_pseg(seg);
     struct pci_dev *pdev = NULL;
@@ -1337,12 +1337,12 @@ int iommu_remove_device(struct pci_dev *
  * If the device isn't owned by the hardware domain, it means it already
  * has been assigned to other domain, or it doesn't exist.
  */
-static int device_assigned(u16 seg, u8 bus, u8 devfn)
+static int device_assigned(const struct domain *d, u16 seg, u8 bus, u8 devfn)
 {
-    struct pci_dev *pdev;
+    const struct pci_dev *pdev;
 
     pcidevs_lock();
-    pdev = pci_get_pdev_by_domain(hardware_domain, seg, bus, devfn);
+    pdev = pci_get_pdev_by_domain(d ?: hardware_domain, seg, bus, devfn);
     pcidevs_unlock();
 
     return pdev ? 0 : -EBUSY;
@@ -1590,7 +1590,7 @@ int iommu_do_pci_domctl(
 
         machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
 
-        ret = xsm_test_assign_device(XSM_HOOK, machine_sbdf);
+        ret = xsm_test_assign_device(XSM_HOOK, d, machine_sbdf);
         if ( ret )
             break;
 
@@ -1598,13 +1598,12 @@ int iommu_do_pci_domctl(
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
 
-        if ( device_assigned(seg, bus, devfn) )
-        {
+        ret = device_assigned(d, seg, bus, devfn);
+        if ( ret && !d )
             printk(XENLOG_G_INFO
                    "%04x:%02x:%02x.%u already assigned, or non-existent\n",
                    seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-            ret = -EINVAL;
-        }
+
         break;
 
     case XEN_DOMCTL_assign_device:
@@ -1634,7 +1633,7 @@ int iommu_do_pci_domctl(
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
 
-        ret = device_assigned(seg, bus, devfn) ?:
+        ret = device_assigned(NULL, seg, bus, devfn) ?:
               assign_device(d, seg, bus, devfn, flags);
         if ( ret == -ERESTART )
             ret = hypercall_create_continuation(__HYPERVISOR_domctl,
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -506,7 +506,11 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendt
 
 /* Assign a device to a guest. Sets up IOMMU structures. */
 /* XEN_DOMCTL_assign_device */
-/* XEN_DOMCTL_test_assign_device */
+/*
+ * XEN_DOMCTL_test_assign_device: Pass DOMID_INVALID to find out whether the
+ * given device is assigned to a DomU at all. Pass a specific domain ID to
+ * find out whether the given device is assigned to that domain.
+ */
 /*
  * XEN_DOMCTL_deassign_device: The behavior of this DOMCTL differs
  * between the different type of device:
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -125,8 +125,8 @@ int pci_ro_device(int seg, int bus, int
 int pci_hide_device(int bus, int devfn);
 struct pci_dev *pci_get_pdev(int seg, int bus, int devfn);
 struct pci_dev *pci_get_real_pdev(int seg, int bus, int devfn);
-struct pci_dev *pci_get_pdev_by_domain(
-    struct domain *, int seg, int bus, int devfn);
+struct pci_dev *pci_get_pdev_by_domain(const struct domain *,
+                                       int seg, int bus, int devfn);
 void pci_check_disable_device(u16 seg, u8 bus, u8 devfn);
 
 uint8_t pci_conf_read8(
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -337,10 +337,11 @@ static XSM_INLINE int xsm_get_device_gro
     return xsm_default_action(action, current->domain, NULL);
 }
 
-static XSM_INLINE int xsm_test_assign_device(XSM_DEFAULT_ARG uint32_t 
machine_bdf)
+static XSM_INLINE int xsm_test_assign_device(XSM_DEFAULT_ARG struct domain *d,
+                                             uint32_t machine_bdf)
 {
     XSM_ASSERT_ACTION(XSM_HOOK);
-    return xsm_default_action(action, current->domain, NULL);
+    return xsm_default_action(action, current->domain, d);
 }
 
 static XSM_INLINE int xsm_assign_device(XSM_DEFAULT_ARG struct domain *d, 
uint32_t machine_bdf)
@@ -358,10 +359,11 @@ static XSM_INLINE int xsm_deassign_devic
 #endif /* HAS_PASSTHROUGH && HAS_PCI */
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
-static XSM_INLINE int xsm_test_assign_dtdevice(XSM_DEFAULT_ARG const char 
*dtpath)
+static XSM_INLINE int xsm_test_assign_dtdevice(XSM_DEFAULT_ARG struct domain 
*d,
+                                               const char *dtpath)
 {
     XSM_ASSERT_ACTION(XSM_HOOK);
-    return xsm_default_action(action, current->domain, NULL);
+    return xsm_default_action(action, current->domain, d);
 }
 
 static XSM_INLINE int xsm_assign_dtdevice(XSM_DEFAULT_ARG struct domain *d,
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -109,13 +109,13 @@ struct xsm_operations {
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
     int (*get_device_group) (uint32_t machine_bdf);
-    int (*test_assign_device) (uint32_t machine_bdf);
+    int (*test_assign_device) (struct domain *d, uint32_t machine_bdf);
     int (*assign_device) (struct domain *d, uint32_t machine_bdf);
     int (*deassign_device) (struct domain *d, uint32_t machine_bdf);
 #endif
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
-    int (*test_assign_dtdevice) (const char *dtpath);
+    int (*test_assign_dtdevice) (struct domain *d, const char *dtpath);
     int (*assign_dtdevice) (struct domain *d, const char *dtpath);
     int (*deassign_dtdevice) (struct domain *d, const char *dtpath);
 #endif
@@ -465,9 +465,9 @@ static inline int xsm_get_device_group(x
     return xsm_ops->get_device_group(machine_bdf);
 }
 
-static inline int xsm_test_assign_device(xsm_default_t def, uint32_t 
machine_bdf)
+static inline int xsm_test_assign_device(xsm_default_t def, struct domain *d, 
uint32_t machine_bdf)
 {
-    return xsm_ops->test_assign_device(machine_bdf);
+    return xsm_ops->test_assign_device(d, machine_bdf);
 }
 
 static inline int xsm_assign_device(xsm_default_t def, struct domain *d, 
uint32_t machine_bdf)
@@ -488,10 +488,10 @@ static inline int xsm_assign_dtdevice(xs
     return xsm_ops->assign_dtdevice(d, dtpath);
 }
 
-static inline int xsm_test_assign_dtdevice(xsm_default_t def,
+static inline int xsm_test_assign_dtdevice(xsm_default_t def, struct domain *d,
                                            const char *dtpath)
 {
-    return xsm_ops->test_assign_dtdevice(dtpath);
+    return xsm_ops->test_assign_dtdevice(d, dtpath);
 }
 
 static inline int xsm_deassign_dtdevice(xsm_default_t def, struct domain *d,
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -1260,7 +1260,7 @@ static int flask_get_device_group(uint32
     return avc_current_has_perm(rsid, SECCLASS_RESOURCE, 
RESOURCE__STAT_DEVICE, NULL);
 }
 
-static int flask_test_assign_device(uint32_t machine_bdf)
+static int flask_test_assign_device(struct domain *d, uint32_t machine_bdf)
 {
     u32 rsid;
     int rc = -EPERM;
@@ -1314,7 +1314,7 @@ static int flask_deassign_device(struct
 #endif /* HAS_PASSTHROUGH && HAS_PCI */
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
-static int flask_test_assign_dtdevice(const char *dtpath)
+static int flask_test_assign_dtdevice(struct domain *d, const char *dtpath)
 {
     u32 rsid;
     int rc = -EPERM;


Attachment: domctl-test-assign-rework.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.