From: Baolu Lu <baolu.lu@linux.intel.com>
To: Jason Gunthorpe <jgg@ziepe.ca>
Cc: baolu.lu@linux.intel.com, Joerg Roedel <joro@8bytes.org>,
Will Deacon <will@kernel.org>,
Robin Murphy <robin.murphy@arm.com>,
Kevin Tian <kevin.tian@intel.com>,
Jean-Philippe Brucker <jean-philippe@linaro.org>,
Nicolin Chen <nicolinc@nvidia.com>, Yi Liu <yi.l.liu@intel.com>,
Jacob Pan <jacob.jun.pan@linux.intel.com>,
Longfang Liu <liulongfang@huawei.com>,
Yan Zhao <yan.y.zhao@intel.com>,
iommu@lists.linux.dev, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v8 12/12] iommu: Use refcount for fault data access
Date: Tue, 12 Dec 2023 11:44:14 +0800 [thread overview]
Message-ID: <62131360-e270-4ea5-92cb-8dd790be8779@linux.intel.com> (raw)
In-Reply-To: <20231211151235.GA1489931@ziepe.ca>
On 12/11/23 11:12 PM, Jason Gunthorpe wrote:
> On Thu, Dec 07, 2023 at 02:43:08PM +0800, Lu Baolu wrote:
>> +/*
>> + * Return the fault parameter of a device if it exists. Otherwise, return NULL.
>> + * On a successful return, the caller takes a reference of this parameter and
>> + * should put it after use by calling iopf_put_dev_fault_param().
>> + */
>> +static struct iommu_fault_param *iopf_get_dev_fault_param(struct device *dev)
>> +{
>> + struct dev_iommu *param = dev->iommu;
>> + struct iommu_fault_param *fault_param;
>> +
>> + if (!param)
>> + return NULL;
>
> Is it actually possible to call this function on a device that does
> not have an iommu driver probed? I'd be surprised by that, maybe this
> should be WARN_ONE
Above check seems to be unnecessary. This helper should only be used
during the iommu probe and release. We can just remove it as any drivers
that abuse this will generate a null-pointer reference warning.
>
>> +
>> + rcu_read_lock();
>> + fault_param = param->fault_param;
>
> The RCU stuff is not right, like this:
>
> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
> index 2ace32c6d13bf3..0258f79c8ddf98 100644
> --- a/drivers/iommu/io-pgfault.c
> +++ b/drivers/iommu/io-pgfault.c
> @@ -40,7 +40,7 @@ static struct iommu_fault_param *iopf_get_dev_fault_param(struct device *dev)
> return NULL;
>
> rcu_read_lock();
> - fault_param = param->fault_param;
> + fault_param = rcu_dereference(param->fault_param);
> if (fault_param && !refcount_inc_not_zero(&fault_param->users))
> fault_param = NULL;
> rcu_read_unlock();
> @@ -51,17 +51,8 @@ static struct iommu_fault_param *iopf_get_dev_fault_param(struct device *dev)
> /* Caller must hold a reference of the fault parameter. */
> static void iopf_put_dev_fault_param(struct iommu_fault_param *fault_param)
> {
> - struct dev_iommu *param = fault_param->dev->iommu;
> -
> - rcu_read_lock();
> - if (!refcount_dec_and_test(&fault_param->users)) {
> - rcu_read_unlock();
> - return;
> - }
> - rcu_read_unlock();
> -
> - param->fault_param = NULL;
> - kfree_rcu(fault_param, rcu);
> + if (refcount_dec_and_test(&fault_param->users))
> + kfree_rcu(fault_param, rcu);
> }
>
> /**
> @@ -174,7 +165,7 @@ static int iommu_handle_iopf(struct iommu_fault *fault,
> }
>
> mutex_unlock(&iopf_param->lock);
> - ret = domain->iopf_handler(group);
> + ret = domain->iopf_handler(iopf_param, group);
> mutex_lock(&iopf_param->lock);
> if (ret)
> iopf_free_group(group);
> @@ -398,7 +389,8 @@ int iopf_queue_add_device(struct iopf_queue *queue, struct device *dev)
>
> mutex_lock(&queue->lock);
> mutex_lock(¶m->lock);
> - if (param->fault_param) {
> + if (rcu_dereference_check(param->fault_param,
> + lockdep_is_held(¶m->lock))) {
> ret = -EBUSY;
> goto done_unlock;
> }
> @@ -418,7 +410,7 @@ int iopf_queue_add_device(struct iopf_queue *queue, struct device *dev)
> list_add(&fault_param->queue_list, &queue->devices);
> fault_param->queue = queue;
>
> - param->fault_param = fault_param;
> + rcu_assign_pointer(param->fault_param, fault_param);
>
> done_unlock:
> mutex_unlock(¶m->lock);
> @@ -442,10 +434,12 @@ int iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev)
> int ret = 0;
> struct iopf_fault *iopf, *next;
> struct dev_iommu *param = dev->iommu;
> - struct iommu_fault_param *fault_param = param->fault_param;
> + struct iommu_fault_param *fault_param;
>
> mutex_lock(&queue->lock);
> mutex_lock(¶m->lock);
> + fault_param = rcu_dereference_check(param->fault_param,
> + lockdep_is_held(¶m->lock));
> if (!fault_param) {
> ret = -ENODEV;
> goto unlock;
> @@ -467,7 +461,10 @@ int iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev)
> list_for_each_entry_safe(iopf, next, &fault_param->partial, list)
> kfree(iopf);
>
> - iopf_put_dev_fault_param(fault_param);
> + /* dec the ref owned by iopf_queue_add_device() */
> + rcu_assign_pointer(param->fault_param, NULL);
> + if (refcount_dec_and_test(&fault_param->users))
> + kfree_rcu(fault_param, rcu);
> unlock:
> mutex_unlock(¶m->lock);
> mutex_unlock(&queue->lock);
> diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
> index 325d1810e133a1..63c1a233a7e91f 100644
> --- a/drivers/iommu/iommu-sva.c
> +++ b/drivers/iommu/iommu-sva.c
> @@ -232,10 +232,9 @@ static void iommu_sva_handle_iopf(struct work_struct *work)
> iopf_free_group(group);
> }
>
> -static int iommu_sva_iopf_handler(struct iopf_group *group)
> +static int iommu_sva_iopf_handler(struct iommu_fault_param *fault_param,
> + struct iopf_group *group)
> {
> - struct iommu_fault_param *fault_param = group->dev->iommu->fault_param;
> -
> INIT_WORK(&group->work, iommu_sva_handle_iopf);
> if (!queue_work(fault_param->queue->wq, &group->work))
> return -EBUSY;
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 8020bb44a64ab1..e16fa9811d5023 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -41,6 +41,7 @@ struct iommu_dirty_ops;
> struct notifier_block;
> struct iommu_sva;
> struct iommu_dma_cookie;
> +struct iommu_fault_param;
>
> #define IOMMU_FAULT_PERM_READ (1 << 0) /* read */
> #define IOMMU_FAULT_PERM_WRITE (1 << 1) /* write */
> @@ -210,7 +211,8 @@ struct iommu_domain {
> unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */
> struct iommu_domain_geometry geometry;
> struct iommu_dma_cookie *iova_cookie;
> - int (*iopf_handler)(struct iopf_group *group);
> + int (*iopf_handler)(struct iommu_fault_param *fault_param,
> + struct iopf_group *group);
How about folding fault_param into iopf_group?
iopf_group is the central data around a iopf handling. The iopf_group
holds the reference count of the device's fault parameter structure
throughout its entire lifecycle.
> void *fault_data;
> union {
> struct {
> @@ -637,7 +639,7 @@ struct iommu_fault_param {
> */
> struct dev_iommu {
> struct mutex lock;
> - struct iommu_fault_param *fault_param;
> + struct iommu_fault_param __rcu *fault_param;
> struct iommu_fwspec *fwspec;
> struct iommu_device *iommu_dev;
> void *priv;
The iommu_page_response() needs to change accordingly which is pointed
out in the next email.
Others look good to me. Thank you so much!
Best regards,
baolu
next prev parent reply other threads:[~2023-12-12 3:48 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-07 6:42 [PATCH v8 00/12] iommu: Prepare to deliver page faults to user space Lu Baolu
2023-12-07 6:42 ` [PATCH v8 01/12] iommu: Move iommu fault data to linux/iommu.h Lu Baolu
2023-12-07 6:42 ` [PATCH v8 02/12] iommu/arm-smmu-v3: Remove unrecoverable faults reporting Lu Baolu
2023-12-07 6:42 ` [PATCH v8 03/12] iommu: Remove unrecoverable fault data Lu Baolu
2023-12-07 6:43 ` [PATCH v8 04/12] iommu: Cleanup iopf data structure definitions Lu Baolu
2023-12-07 6:43 ` [PATCH v8 05/12] iommu: Merge iopf_device_param into iommu_fault_param Lu Baolu
2023-12-07 6:43 ` [PATCH v8 06/12] iommu: Remove iommu_[un]register_device_fault_handler() Lu Baolu
2023-12-07 6:43 ` [PATCH v8 07/12] iommu: Merge iommu_fault_event and iopf_fault Lu Baolu
2023-12-07 6:43 ` [PATCH v8 08/12] iommu: Prepare for separating SVA and IOPF Lu Baolu
2023-12-07 6:43 ` [PATCH v8 09/12] iommu: Make iommu_queue_iopf() more generic Lu Baolu
2023-12-07 6:43 ` [PATCH v8 10/12] iommu: Separate SVA and IOPF Lu Baolu
2023-12-07 6:43 ` [PATCH v8 11/12] iommu: Refine locking for per-device fault data management Lu Baolu
2023-12-11 14:50 ` Jason Gunthorpe
2023-12-07 6:43 ` [PATCH v8 12/12] iommu: Use refcount for fault data access Lu Baolu
2023-12-11 15:12 ` Jason Gunthorpe
2023-12-12 3:44 ` Baolu Lu [this message]
2023-12-12 15:18 ` Jason Gunthorpe
2023-12-11 15:24 ` Jason Gunthorpe
2023-12-12 5:07 ` Baolu Lu
2023-12-12 15:18 ` Jason Gunthorpe
2023-12-13 2:19 ` Baolu Lu
2023-12-12 5:17 ` Baolu Lu
2023-12-12 15:14 ` Jason Gunthorpe
2023-12-13 2:14 ` Baolu Lu
2023-12-12 5:23 ` Baolu Lu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=62131360-e270-4ea5-92cb-8dd790be8779@linux.intel.com \
--to=baolu.lu@linux.intel.com \
--cc=iommu@lists.linux.dev \
--cc=jacob.jun.pan@linux.intel.com \
--cc=jean-philippe@linaro.org \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=liulongfang@huawei.com \
--cc=nicolinc@nvidia.com \
--cc=robin.murphy@arm.com \
--cc=will@kernel.org \
--cc=yan.y.zhao@intel.com \
--cc=yi.l.liu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox