iommu/amd: Lock dev_data in attach/detach code paths
authorJoerg Roedel <jroedel@suse.de>
Wed, 25 Sep 2019 13:22:59 +0000 (15:22 +0200)
committerJoerg Roedel <jroedel@suse.de>
Sat, 28 Sep 2019 12:44:04 +0000 (14:44 +0200)
Make sure that attaching a detaching a device can't race against each
other and protect the iommu_dev_data with a spin_lock in these code
paths.

Fixes: 92d420ec028d ("iommu/amd: Relax locking in dma_ops path")
Reviewed-by: Filippo Sironi <sironi@amazon.de>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_types.h

index 459247c32dc0e299a8db171733736acd52fea1ca..bac4e20a591957b8d2b6897fb3edc5dbb01d4404 100644 (file)
@@ -201,6 +201,7 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid)
        if (!dev_data)
                return NULL;
 
+       spin_lock_init(&dev_data->lock);
        dev_data->devid = devid;
        ratelimit_default_init(&dev_data->rs);
 
@@ -2157,6 +2158,8 @@ static int attach_device(struct device *dev,
 
        dev_data = get_dev_data(dev);
 
+       spin_lock(&dev_data->lock);
+
        ret = -EBUSY;
        if (dev_data->domain != NULL)
                goto out;
@@ -2199,6 +2202,8 @@ skip_ats_check:
        domain_flush_complete(domain);
 
 out:
+       spin_unlock(&dev_data->lock);
+
        spin_unlock_irqrestore(&domain->lock, flags);
 
        return ret;
@@ -2218,6 +2223,8 @@ static void detach_device(struct device *dev)
 
        spin_lock_irqsave(&domain->lock, flags);
 
+       spin_lock(&dev_data->lock);
+
        /*
         * First check if the device is still attached. It might already
         * be detached from its domain because the generic
@@ -2240,6 +2247,8 @@ static void detach_device(struct device *dev)
        dev_data->ats.enabled = false;
 
 out:
+       spin_unlock(&dev_data->lock);
+
        spin_unlock_irqrestore(&domain->lock, flags);
 }
 
index 0186501ab9717b624643a402a95f079e39d4decb..c9c1612d52e00090a2fb1a4e374e9468ba25607e 100644 (file)
@@ -633,6 +633,9 @@ struct devid_map {
  * This struct contains device specific data for the IOMMU
  */
 struct iommu_dev_data {
+       /*Protect against attach/detach races */
+       spinlock_t lock;
+
        struct list_head list;            /* For domain->dev_list */
        struct llist_node dev_data_list;  /* For global dev_data_list */
        struct protection_domain *domain; /* Domain the device is bound to */