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

[Xen-devel] [PATCH v2] 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 can be assigned to a particular domain.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
v2: Alter the semantics to check whether the device can be assigned to
    the passed in domain.
TBD: It's not clear to me whether the test-assign XSM hooks are still
     useful this way.

--- 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
@@ -143,12 +143,15 @@ int iommu_do_dt_domctl(struct xen_domctl
     switch ( domctl->cmd )
     {
     case XEN_DOMCTL_assign_device:
+        ASSERT(d);
+        /* fall through */
+    case XEN_DOMCTL_test_assign_device:
         ret = -ENODEV;
         if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
             break;
 
         ret = -EINVAL;
-        if ( d->is_dying || domctl->u.assign_device.flags )
+        if ( (d && d->is_dying) || domctl->u.assign_device.flags )
             break;
 
         ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
@@ -157,10 +160,22 @@ int iommu_do_dt_domctl(struct xen_domctl
         if ( ret )
             break;
 
-        ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
+        ret = d ? xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev))
+                : xsm_test_assign_dtdevice(XSM_HOOK, dt_node_full_name(dev));
         if ( ret )
             break;
 
+        if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
+        {
+            if ( iommu_dt_device_is_assigned(dev) )
+            {
+                printk(XENLOG_G_ERR "%s already assigned.\n",
+                       dt_node_full_name(dev));
+                ret = -EINVAL;
+            }
+            break;
+        }
+
         ret = iommu_assign_dt_device(d, dev);
 
         if ( ret )
@@ -194,33 +209,6 @@ int iommu_do_dt_domctl(struct xen_domctl
                    dt_node_full_name(dev), d->domain_id, ret);
         break;
 
-    case XEN_DOMCTL_test_assign_device:
-        ret = -ENODEV;
-        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
-            break;
-
-        ret = -EINVAL;
-        if ( domctl->u.assign_device.flags )
-            break;
-
-        ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
-                                    domctl->u.assign_device.u.dt.size,
-                                    &dev);
-        if ( ret )
-            break;
-
-        ret = xsm_test_assign_dtdevice(XSM_HOOK, dt_node_full_name(dev));
-        if ( ret )
-            break;
-
-        if ( iommu_dt_device_is_assigned(dev) )
-        {
-            printk(XENLOG_G_ERR "%s already assigned.\n",
-                   dt_node_full_name(dev));
-            ret = -EINVAL;
-        }
-        break;
-
     default:
         ret = -ENOSYS;
         break;
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1579,35 +1579,10 @@ int iommu_do_pci_domctl(
     }
     break;
 
-    case XEN_DOMCTL_test_assign_device:
-        ret = -ENODEV;
-        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_PCI )
-            break;
-
-        ret = -EINVAL;
-        if ( domctl->u.assign_device.flags )
-            break;
-
-        machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
-
-        ret = xsm_test_assign_device(XSM_HOOK, machine_sbdf);
-        if ( ret )
-            break;
-
-        seg = machine_sbdf >> 16;
-        bus = PCI_BUS(machine_sbdf);
-        devfn = PCI_DEVFN2(machine_sbdf);
-
-        if ( device_assigned(seg, bus, devfn) )
-        {
-            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:
+        ASSERT(d);
+        /* fall through */
+    case XEN_DOMCTL_test_assign_device:
         /* Don't support self-assignment of devices. */
         if ( d == current->domain )
         {
@@ -1621,12 +1596,15 @@ int iommu_do_pci_domctl(
 
         ret = -EINVAL;
         flags = domctl->u.assign_device.flags;
-        if ( d->is_dying || (flags & ~XEN_DOMCTL_DEV_RDM_RELAXED) )
+        if ( domctl->cmd == XEN_DOMCTL_assign_device
+             ? d->is_dying || (flags & ~XEN_DOMCTL_DEV_RDM_RELAXED)
+             : flags )
             break;
 
         machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
 
-        ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf);
+        ret = d ? xsm_assign_device(XSM_HOOK, d, machine_sbdf)
+                : xsm_test_assign_device(XSM_HOOK, machine_sbdf);
         if ( ret )
             break;
 
@@ -1634,8 +1612,20 @@ int iommu_do_pci_domctl(
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
 
-        ret = device_assigned(seg, bus, devfn) ?:
-              assign_device(d, seg, bus, devfn, flags);
+        ret = device_assigned(seg, bus, devfn);
+        if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
+        {
+            if ( ret )
+            {
+                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;
+        }
+        if ( !ret )
+            ret = assign_device(d, seg, bus, devfn, flags);
         if ( ret == -ERESTART )
             ret = hypercall_create_continuation(__HYPERVISOR_domctl,
                                                 "h", u_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 any DomU at all. Pass a specific domain ID to
+ * find out whether the given device can be assigned to that domain.
+ */
 /*
  * XEN_DOMCTL_deassign_device: The behavior of this DOMCTL differs
  * between the different type of device:



_______________________________________________
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®.