@@ -2098,6 +2098,9 @@ void unflatten_device_tree(const void *fdt, struct dt_device_node **mynodes)
*allnextp = NULL;
dt_dprintk(" <- unflatten_device_tree()\n");
+
+ /* Init r/w lock for host device tree. */
+ rwlock_init(&dt_host->lock);
}
static void dt_alias_add(struct dt_alias_prop *ap,
@@ -112,6 +112,8 @@ int iommu_release_dt_devices(struct domain *d)
if ( !is_iommu_enabled(d) )
return 0;
+ read_lock(&dt_host->lock);
+
list_for_each_entry_safe(dev, _dev, &hd->dt_devices, domain_list)
{
rc = iommu_deassign_dt_device(d, dev);
@@ -119,10 +121,14 @@ int iommu_release_dt_devices(struct domain *d)
{
dprintk(XENLOG_ERR, "Failed to deassign %s in domain %u\n",
dt_node_full_name(dev), d->domain_id);
+
+ read_unlock(&dt_host->lock);
return rc;
}
}
+ read_unlock(&dt_host->lock);
+
return 0;
}
@@ -259,11 +265,15 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
spin_lock(&dtdevs_lock);
+ read_lock(&dt_host->lock);
+
ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
domctl->u.assign_device.u.dt.size,
&dev);
if ( ret )
{
+ read_unlock(&dt_host->lock);
+
spin_unlock(&dtdevs_lock);
break;
@@ -272,6 +282,8 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
if ( ret )
{
+ read_unlock(&dt_host->lock);
+
spin_unlock(&dtdevs_lock);
break;
@@ -287,6 +299,8 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
ret = -EINVAL;
}
+ read_unlock(&dt_host->lock);
+
spin_unlock(&dtdevs_lock);
break;
@@ -295,22 +309,31 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
spin_unlock(&dtdevs_lock);
if ( d == dom_io )
+ {
+ read_unlock(&dt_host->lock);
return -EINVAL;
+ }
ret = iommu_add_dt_device(dev);
if ( ret < 0 )
{
printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
dt_node_full_name(dev));
+
+ read_unlock(&dt_host->lock);
break;
}
ret = iommu_assign_dt_device(d, dev);
if ( ret )
+ {
printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
" to dom%u failed (%d)\n",
dt_node_full_name(dev), d->domain_id, ret);
+ }
+
+ read_unlock(&dt_host->lock);
break;
case XEN_DOMCTL_deassign_device:
@@ -322,25 +345,41 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
if ( domctl->u.assign_device.flags )
break;
+ read_lock(&dt_host->lock);
+
ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
domctl->u.assign_device.u.dt.size,
&dev);
if ( ret )
+ {
+ read_unlock(&dt_host->lock);
break;
+ }
ret = xsm_deassign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
+
if ( ret )
+ {
+ read_unlock(&dt_host->lock);
break;
+ }
if ( d == dom_io )
+ {
+ read_unlock(&dt_host->lock);
return -EINVAL;
+ }
ret = iommu_deassign_dt_device(d, dev);
if ( ret )
+ {
printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
" to dom%u failed (%d)\n",
dt_node_full_name(dev), d->domain_id, ret);
+ }
+
+ read_unlock(&dt_host->lock);
break;
default:
@@ -18,6 +18,7 @@
#include <xen/string.h>
#include <xen/types.h>
#include <xen/list.h>
+#include <xen/rwlock.h>
#define DEVICE_TREE_MAX_DEPTH 16
@@ -106,6 +107,11 @@ struct dt_device_node {
struct list_head domain_list;
struct device dev;
+
+ /*
+ * Lock that protects r/w updates to unflattened device tree i.e. dt_host.
+ */
+ rwlock_t lock;
};
#define dt_to_dev(dt_node) (&(dt_node)->dev)
Dynamic programming ops will modify the dt_host and there might be other function which are browsing the dt_host at the same time. To avoid the race conditions, adding rwlock for browsing the dt_host during runtime. Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com> --- xen/common/device_tree.c | 3 +++ xen/drivers/passthrough/device_tree.c | 39 +++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 6 +++++ 3 files changed, 48 insertions(+)