Skip to content

Commit 831b40f

Browse files
yiliu1765jgunthorpe
authored andcommitted
iommufd/device: Replace device_list with device_array
igroup->attach->device_list is used to track attached device of a group in the RID path. Such tracking is also needed in the PASID path in order to share path with the RID path. While there is only one list_head in the iommufd_device. It cannot work if the device has been attached in both RID path and PASID path. To solve it, replacing the device_list with an xarray. The attached iommufd_device is stored in the entry indexed by the idev->obj.id. Link: https://patch.msgid.link/r/[email protected] Reviewed-by: Nicolin Chen <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Signed-off-by: Yi Liu <[email protected]> Tested-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 75f990a commit 831b40f

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

drivers/iommu/iommufd/device.c

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ MODULE_PARM_DESC(
1919

2020
struct iommufd_attach {
2121
struct iommufd_hw_pagetable *hwpt;
22-
struct list_head device_list;
22+
struct xarray device_array;
2323
};
2424

2525
static void iommufd_group_release(struct kref *kref)
@@ -297,6 +297,20 @@ u32 iommufd_device_to_id(struct iommufd_device *idev)
297297
}
298298
EXPORT_SYMBOL_NS_GPL(iommufd_device_to_id, "IOMMUFD");
299299

300+
static unsigned int iommufd_group_device_num(struct iommufd_group *igroup)
301+
{
302+
struct iommufd_device *idev;
303+
unsigned int count = 0;
304+
unsigned long index;
305+
306+
lockdep_assert_held(&igroup->lock);
307+
308+
if (igroup->attach)
309+
xa_for_each(&igroup->attach->device_array, index, idev)
310+
count++;
311+
return count;
312+
}
313+
300314
#ifdef CONFIG_IRQ_MSI_IOMMU
301315
static int iommufd_group_setup_msi(struct iommufd_group *igroup,
302316
struct iommufd_hwpt_paging *hwpt_paging)
@@ -371,12 +385,7 @@ iommufd_device_attach_reserved_iova(struct iommufd_device *idev,
371385
/* Check if idev is attached to igroup->hwpt */
372386
static bool iommufd_device_is_attached(struct iommufd_device *idev)
373387
{
374-
struct iommufd_device *cur;
375-
376-
list_for_each_entry(cur, &idev->igroup->attach->device_list, group_item)
377-
if (cur == idev)
378-
return true;
379-
return false;
388+
return xa_load(&idev->igroup->attach->device_array, idev->obj.id);
380389
}
381390

382391
static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
@@ -510,20 +519,27 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
510519
rc = -ENOMEM;
511520
goto err_unlock;
512521
}
513-
INIT_LIST_HEAD(&attach->device_list);
522+
xa_init(&attach->device_array);
514523
}
515524

516525
old_hwpt = attach->hwpt;
517526

527+
rc = xa_insert(&attach->device_array, idev->obj.id, XA_ZERO_ENTRY,
528+
GFP_KERNEL);
529+
if (rc) {
530+
WARN_ON(rc == -EBUSY && !old_hwpt);
531+
goto err_free_attach;
532+
}
533+
518534
if (old_hwpt && old_hwpt != hwpt) {
519535
rc = -EINVAL;
520-
goto err_free_attach;
536+
goto err_release_devid;
521537
}
522538

523539
if (attach_resv) {
524540
rc = iommufd_device_attach_reserved_iova(idev, hwpt_paging);
525541
if (rc)
526-
goto err_free_attach;
542+
goto err_release_devid;
527543
}
528544

529545
/*
@@ -541,12 +557,15 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
541557
igroup->attach = attach;
542558
}
543559
refcount_inc(&hwpt->obj.users);
544-
list_add_tail(&idev->group_item, &attach->device_list);
560+
WARN_ON(xa_is_err(xa_store(&attach->device_array, idev->obj.id,
561+
idev, GFP_KERNEL)));
545562
mutex_unlock(&igroup->lock);
546563
return 0;
547564
err_unresv:
548565
if (attach_resv)
549566
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
567+
err_release_devid:
568+
xa_release(&attach->device_array, idev->obj.id);
550569
err_free_attach:
551570
if (iommufd_group_first_attach(igroup, pasid))
552571
kfree(attach);
@@ -568,8 +587,8 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev, ioasid_t pasid)
568587
hwpt = attach->hwpt;
569588
hwpt_paging = find_hwpt_paging(hwpt);
570589

571-
list_del(&idev->group_item);
572-
if (list_empty(&attach->device_list)) {
590+
xa_erase(&attach->device_array, idev->obj.id);
591+
if (xa_empty(&attach->device_array)) {
573592
iommufd_hwpt_detach_device(hwpt, idev, pasid);
574593
igroup->attach = NULL;
575594
kfree(attach);
@@ -599,10 +618,11 @@ iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
599618
struct iommufd_hwpt_paging *hwpt_paging)
600619
{
601620
struct iommufd_device *cur;
621+
unsigned long index;
602622

603623
lockdep_assert_held(&igroup->lock);
604624

605-
list_for_each_entry(cur, &igroup->attach->device_list, group_item)
625+
xa_for_each(&igroup->attach->device_array, index, cur)
606626
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, cur->dev);
607627
}
608628

@@ -612,14 +632,14 @@ iommufd_group_do_replace_reserved_iova(struct iommufd_group *igroup,
612632
{
613633
struct iommufd_hwpt_paging *old_hwpt_paging;
614634
struct iommufd_device *cur;
635+
unsigned long index;
615636
int rc;
616637

617638
lockdep_assert_held(&igroup->lock);
618639

619640
old_hwpt_paging = find_hwpt_paging(igroup->attach->hwpt);
620641
if (!old_hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas) {
621-
list_for_each_entry(cur,
622-
&igroup->attach->device_list, group_item) {
642+
xa_for_each(&igroup->attach->device_array, index, cur) {
623643
rc = iopt_table_enforce_dev_resv_regions(
624644
&hwpt_paging->ioas->iopt, cur->dev, NULL);
625645
if (rc)
@@ -660,7 +680,7 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
660680

661681
old_hwpt = attach->hwpt;
662682

663-
WARN_ON(!old_hwpt || list_empty(&attach->device_list));
683+
WARN_ON(!old_hwpt || xa_empty(&attach->device_array));
664684

665685
if (!iommufd_device_is_attached(idev)) {
666686
rc = -EINVAL;
@@ -689,9 +709,9 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
689709

690710
attach->hwpt = hwpt;
691711

692-
num_devices = list_count_nodes(&attach->device_list);
712+
num_devices = iommufd_group_device_num(igroup);
693713
/*
694-
* Move the refcounts held by the device_list to the new hwpt. Retain a
714+
* Move the refcounts held by the device_array to the new hwpt. Retain a
695715
* refcount for this thread as the caller will free it.
696716
*/
697717
refcount_add(num_devices, &hwpt->obj.users);

0 commit comments

Comments
 (0)