lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 24 Jul 2022 21:48:15 +0800
From:   Baolu Lu <baolu.lu@...ux.intel.com>
To:     Jason Gunthorpe <jgg@...dia.com>
Cc:     baolu.lu@...ux.intel.com, Joerg Roedel <joro@...tes.org>,
        Christoph Hellwig <hch@...radead.org>,
        Kevin Tian <kevin.tian@...el.com>,
        Ashok Raj <ashok.raj@...el.com>, Will Deacon <will@...nel.org>,
        Robin Murphy <robin.murphy@....com>,
        Jean-Philippe Brucker <jean-philippe@...aro.com>,
        Dave Jiang <dave.jiang@...el.com>,
        Vinod Koul <vkoul@...nel.org>,
        Eric Auger <eric.auger@...hat.com>,
        Liu Yi L <yi.l.liu@...el.com>,
        Jacob jun Pan <jacob.jun.pan@...el.com>,
        Zhangfei Gao <zhangfei.gao@...aro.org>,
        Zhu Tony <tony.zhu@...el.com>, iommu@...ts.linux.dev,
        linux-kernel@...r.kernel.org
Subject: Re: [PATCH v10 08/12] iommu/sva: Refactoring
 iommu_sva_bind/unbind_device()

On 2022/7/23 22:26, Jason Gunthorpe wrote:
> On Tue, Jul 05, 2022 at 01:07:06PM +0800, Lu Baolu wrote:
>> The existing iommu SVA interfaces are implemented by calling the SVA
>> specific iommu ops provided by the IOMMU drivers. There's no need for
>> any SVA specific ops in iommu_ops vector anymore as we can achieve
>> this through the generic attach/detach_dev_pasid domain ops.
>>
>> This refactors the IOMMU SVA interfaces implementation by using the
>> set/block_pasid_dev ops and align them with the concept of the SVA
>> iommu domain. Put the new SVA code in the sva related file in order
>> to make it self-contained.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@...ux.intel.com>
>> Tested-by: Zhangfei Gao <zhangfei.gao@...aro.org>
>> Tested-by: Tony Zhu <tony.zhu@...el.com>
>> ---
>>   include/linux/iommu.h         |  67 +++++++++++--------
>>   drivers/iommu/iommu-sva-lib.c |  98 ++++++++++++++++++++++++++++
>>   drivers/iommu/iommu.c         | 119 ++++++++--------------------------
>>   3 files changed, 165 insertions(+), 119 deletions(-)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 42f0418dc22c..f59b0ecd3995 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -39,7 +39,6 @@ struct device;
>>   struct iommu_domain;
>>   struct iommu_domain_ops;
>>   struct notifier_block;
>> -struct iommu_sva;
>>   struct iommu_fault_event;
>>   struct iommu_dma_cookie;
>>   
>> @@ -57,6 +56,14 @@ struct iommu_domain_geometry {
>>   	bool force_aperture;       /* DMA only allowed in mappable range? */
>>   };
>>   
>> +/**
>> + * struct iommu_sva - handle to a device-mm bond
>> + */
>> +struct iommu_sva {
>> +	struct device		*dev;
>> +	refcount_t		users;
>> +};
>> +
>>   /* Domain feature flags */
>>   #define __IOMMU_DOMAIN_PAGING	(1U << 0)  /* Support for iommu_map/unmap */
>>   #define __IOMMU_DOMAIN_DMA_API	(1U << 1)  /* Domain for use in DMA-API
>> @@ -105,6 +112,7 @@ struct iommu_domain {
>>   		};
>>   		struct {	/* IOMMU_DOMAIN_SVA */
>>   			struct mm_struct *mm;
>> +			struct iommu_sva bond;
> 
> We can't store a single struct device inside a domain, this is not
> layed out right.

Yes, agreed.

> 
> The API is really refcounting the PASID:
> 
>> +struct iommu_sva *iommu_sva_bind_device(struct device *dev,
>> +					struct mm_struct *mm);
>> +void iommu_sva_unbind_device(struct iommu_sva *handle);
> 
> So what you need to do is store that 'iommu_sva' in the group's PASID
> xarray.
> 
> The bind logic would be
> 
>    sva = xa_load(group->pasid, mm->pasid)
>    if (sva)
>       refcount_inc(sva->users)
>       return sva
>    sva = kalloc
>    sva->domain = domain
>    xa_store(group->pasid, sva);

Thanks for the suggestion. It makes a lot of sense to me.

Furthermore, I'd like to separate the generic data from the caller-
specific things because the group->pasid_array should also be able to
serve other usages. Hence, the attach/detach_device_pasid interfaces
might be changed like below:

/* Collection of per-pasid IOMMU data */
struct group_pasid {
	struct iommu_domain *domain;
	void *priv;
};

/*
  * iommu_attach_device_pasid() - Attach a domain to pasid of device
  * @domain: the iommu domain.
  * @dev: the attached device.
  * @pasid: the pasid of the device.
  * @data: private data, NULL if not needed.
  *
  * Return: 0 on success, or an error.
  */
int iommu_attach_device_pasid(struct iommu_domain *domain, struct device 
*dev,
			      ioasid_t pasid, void *data)
{
	struct iommu_group *group;
	struct group_pasid *param;
	int ret = -EINVAL;
	void *curr;

	if (!domain->ops->set_dev_pasid)
		return -EOPNOTSUPP;

	group = iommu_group_get(dev);
	if (!group)
		return -ENODEV;

	param = kzalloc(sizeof(*param), GFP_KERNEL);
	if (!param) {
		iommu_group_put(group);
		return -ENOMEM;
	}
	param->domain = domain;
	param->priv = data;

	mutex_lock(&group->mutex);
	if (!iommu_group_immutable_singleton(group, dev))
		goto out_unlock;

	curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, param, GFP_KERNEL);
	if (curr) {
		ret = xa_err(curr) ? : -EBUSY;
		goto out_unlock;
	}
	ret = domain->ops->set_dev_pasid(domain, dev, pasid);
	if (ret)
		xa_erase(&group->pasid_array, pasid);
out_unlock:
	mutex_unlock(&group->mutex);
	iommu_group_put(group);
	if (ret)
		kfree(param);

	return ret;
}

/*
  * iommu_detach_device_pasid() - Detach the domain from pasid of device
  * @domain: the iommu domain.
  * @dev: the attached device.
  * @pasid: the pasid of the device.
  *
  * The @domain must have been attached to @pasid of the @dev with
  * iommu_detach_device_pasid().
  */
void iommu_detach_device_pasid(struct iommu_domain *domain, struct 
device *dev,
			       ioasid_t pasid)
{
	struct iommu_group *group = iommu_group_get(dev);
	struct group_pasid *param;

	mutex_lock(&group->mutex);
	domain->ops->set_dev_pasid(group->blocking_domain, dev, pasid);
	param = xa_erase(&group->pasid_array, pasid);
	WARN_ON(!param || param->domain != domain);
	mutex_unlock(&group->mutex);

	iommu_group_put(group);
	kfree(param);
}

Does this look right to you?

Best regards,
baolu

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ