forked from Minki/linux
iommu/amd: Lock dev_data in attach/detach code paths
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: 92d420ec02
("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>
This commit is contained in:
parent
45e528d9c4
commit
ab7b2577f0
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user