@@ -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+
2025static 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
333337iommufd_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
339343static 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 ;
528547err_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 );
531553err_unlock :
532554 mutex_unlock (& igroup -> lock );
533555 return rc ;
@@ -537,14 +559,20 @@ struct iommufd_hw_pagetable *
537559iommufd_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.
0 commit comments