Skip to content

Commit 75f990a

Browse files
yiliu1765jgunthorpe
authored andcommitted
iommufd/device: Wrap igroup->hwpt and igroup->device_list into attach struct
The igroup->hwpt and igroup->device_list are used to track the hwpt attach of a group in the RID path. While the coming PASID path also needs such tracking. To be prepared, wrap igroup->hwpt and igroup->device_list into attach struct which is allocated per attaching the first device of the group and freed per detaching the last device of the group. Link: https://patch.msgid.link/r/[email protected] Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Lu Baolu <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Signed-off-by: Yi Liu <[email protected]> Tested-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent ba1de6c commit 75f990a

File tree

2 files changed

+58
-23
lines changed

2 files changed

+58
-23
lines changed

drivers/iommu/iommufd/device.c

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ MODULE_PARM_DESC(
1717
"Allow IOMMUFD to bind to devices even if the platform cannot isolate "
1818
"the MSI interrupt window. Enabling this is a security weakness.");
1919

20+
struct iommufd_attach {
21+
struct iommufd_hw_pagetable *hwpt;
22+
struct list_head device_list;
23+
};
24+
2025
static void iommufd_group_release(struct kref *kref)
2126
{
2227
struct iommufd_group *igroup =
2328
container_of(kref, struct iommufd_group, ref);
2429

25-
WARN_ON(igroup->hwpt || !list_empty(&igroup->device_list));
30+
WARN_ON(igroup->attach);
2631

2732
xa_cmpxchg(&igroup->ictx->groups, iommu_group_id(igroup->group), igroup,
2833
NULL, GFP_KERNEL);
@@ -89,7 +94,6 @@ static struct iommufd_group *iommufd_get_group(struct iommufd_ctx *ictx,
8994

9095
kref_init(&new_igroup->ref);
9196
mutex_init(&new_igroup->lock);
92-
INIT_LIST_HEAD(&new_igroup->device_list);
9397
new_igroup->sw_msi_start = PHYS_ADDR_MAX;
9498
/* group reference moves into new_igroup */
9599
new_igroup->group = group;
@@ -333,7 +337,7 @@ static bool
333337
iommufd_group_first_attach(struct iommufd_group *igroup, ioasid_t pasid)
334338
{
335339
lockdep_assert_held(&igroup->lock);
336-
return !igroup->hwpt;
340+
return !igroup->attach;
337341
}
338342

339343
static int
@@ -369,7 +373,7 @@ static bool iommufd_device_is_attached(struct iommufd_device *idev)
369373
{
370374
struct iommufd_device *cur;
371375

372-
list_for_each_entry(cur, &idev->igroup->device_list, group_item)
376+
list_for_each_entry(cur, &idev->igroup->attach->device_list, group_item)
373377
if (cur == idev)
374378
return true;
375379
return false;
@@ -493,19 +497,33 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
493497
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
494498
bool attach_resv = hwpt_paging && pasid == IOMMU_NO_PASID;
495499
struct iommufd_group *igroup = idev->igroup;
500+
struct iommufd_hw_pagetable *old_hwpt;
501+
struct iommufd_attach *attach;
496502
int rc;
497503

498504
mutex_lock(&igroup->lock);
499505

500-
if (igroup->hwpt && igroup->hwpt != hwpt) {
506+
attach = igroup->attach;
507+
if (!attach) {
508+
attach = kzalloc(sizeof(*attach), GFP_KERNEL);
509+
if (!attach) {
510+
rc = -ENOMEM;
511+
goto err_unlock;
512+
}
513+
INIT_LIST_HEAD(&attach->device_list);
514+
}
515+
516+
old_hwpt = attach->hwpt;
517+
518+
if (old_hwpt && old_hwpt != hwpt) {
501519
rc = -EINVAL;
502-
goto err_unlock;
520+
goto err_free_attach;
503521
}
504522

505523
if (attach_resv) {
506524
rc = iommufd_device_attach_reserved_iova(idev, hwpt_paging);
507525
if (rc)
508-
goto err_unlock;
526+
goto err_free_attach;
509527
}
510528

511529
/*
@@ -519,15 +537,19 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
519537
rc = iommufd_hwpt_attach_device(hwpt, idev, pasid);
520538
if (rc)
521539
goto err_unresv;
522-
igroup->hwpt = hwpt;
540+
attach->hwpt = hwpt;
541+
igroup->attach = attach;
523542
}
524543
refcount_inc(&hwpt->obj.users);
525-
list_add_tail(&idev->group_item, &igroup->device_list);
544+
list_add_tail(&idev->group_item, &attach->device_list);
526545
mutex_unlock(&igroup->lock);
527546
return 0;
528547
err_unresv:
529548
if (attach_resv)
530549
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
550+
err_free_attach:
551+
if (iommufd_group_first_attach(igroup, pasid))
552+
kfree(attach);
531553
err_unlock:
532554
mutex_unlock(&igroup->lock);
533555
return rc;
@@ -537,14 +559,20 @@ struct iommufd_hw_pagetable *
537559
iommufd_hw_pagetable_detach(struct iommufd_device *idev, ioasid_t pasid)
538560
{
539561
struct iommufd_group *igroup = idev->igroup;
540-
struct iommufd_hw_pagetable *hwpt = igroup->hwpt;
541-
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
562+
struct iommufd_hwpt_paging *hwpt_paging;
563+
struct iommufd_hw_pagetable *hwpt;
564+
struct iommufd_attach *attach;
542565

543566
mutex_lock(&igroup->lock);
567+
attach = igroup->attach;
568+
hwpt = attach->hwpt;
569+
hwpt_paging = find_hwpt_paging(hwpt);
570+
544571
list_del(&idev->group_item);
545-
if (list_empty(&igroup->device_list)) {
572+
if (list_empty(&attach->device_list)) {
546573
iommufd_hwpt_detach_device(hwpt, idev, pasid);
547-
igroup->hwpt = NULL;
574+
igroup->attach = NULL;
575+
kfree(attach);
548576
}
549577
if (hwpt_paging && pasid == IOMMU_NO_PASID)
550578
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
@@ -574,7 +602,7 @@ iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
574602

575603
lockdep_assert_held(&igroup->lock);
576604

577-
list_for_each_entry(cur, &igroup->device_list, group_item)
605+
list_for_each_entry(cur, &igroup->attach->device_list, group_item)
578606
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, cur->dev);
579607
}
580608

@@ -588,9 +616,10 @@ iommufd_group_do_replace_reserved_iova(struct iommufd_group *igroup,
588616

589617
lockdep_assert_held(&igroup->lock);
590618

591-
old_hwpt_paging = find_hwpt_paging(igroup->hwpt);
619+
old_hwpt_paging = find_hwpt_paging(igroup->attach->hwpt);
592620
if (!old_hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas) {
593-
list_for_each_entry(cur, &igroup->device_list, group_item) {
621+
list_for_each_entry(cur,
622+
&igroup->attach->device_list, group_item) {
594623
rc = iopt_table_enforce_dev_resv_regions(
595624
&hwpt_paging->ioas->iopt, cur->dev, NULL);
596625
if (rc)
@@ -617,27 +646,32 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
617646
struct iommufd_hwpt_paging *old_hwpt_paging;
618647
struct iommufd_group *igroup = idev->igroup;
619648
struct iommufd_hw_pagetable *old_hwpt;
649+
struct iommufd_attach *attach;
620650
unsigned int num_devices;
621651
int rc;
622652

623653
mutex_lock(&igroup->lock);
624654

625-
if (igroup->hwpt == NULL) {
655+
attach = igroup->attach;
656+
if (!attach) {
626657
rc = -EINVAL;
627658
goto err_unlock;
628659
}
629660

661+
old_hwpt = attach->hwpt;
662+
663+
WARN_ON(!old_hwpt || list_empty(&attach->device_list));
664+
630665
if (!iommufd_device_is_attached(idev)) {
631666
rc = -EINVAL;
632667
goto err_unlock;
633668
}
634669

635-
if (hwpt == igroup->hwpt) {
670+
if (hwpt == old_hwpt) {
636671
mutex_unlock(&igroup->lock);
637672
return NULL;
638673
}
639674

640-
old_hwpt = igroup->hwpt;
641675
if (attach_resv) {
642676
rc = iommufd_group_do_replace_reserved_iova(igroup, hwpt_paging);
643677
if (rc)
@@ -653,9 +687,9 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
653687
(!hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas))
654688
iommufd_group_remove_reserved_iova(igroup, old_hwpt_paging);
655689

656-
igroup->hwpt = hwpt;
690+
attach->hwpt = hwpt;
657691

658-
num_devices = list_count_nodes(&igroup->device_list);
692+
num_devices = list_count_nodes(&attach->device_list);
659693
/*
660694
* Move the refcounts held by the device_list to the new hwpt. Retain a
661695
* refcount for this thread as the caller will free it.

drivers/iommu/iommufd/iommufd_private.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,13 +399,14 @@ static inline void iommufd_hw_pagetable_put(struct iommufd_ctx *ictx,
399399
refcount_dec(&hwpt->obj.users);
400400
}
401401

402+
struct iommufd_attach;
403+
402404
struct iommufd_group {
403405
struct kref ref;
404406
struct mutex lock;
405407
struct iommufd_ctx *ictx;
406408
struct iommu_group *group;
407-
struct iommufd_hw_pagetable *hwpt;
408-
struct list_head device_list;
409+
struct iommufd_attach *attach;
409410
struct iommufd_sw_msi_maps required_sw_msi;
410411
phys_addr_t sw_msi_start;
411412
};

0 commit comments

Comments
 (0)