@@ -19,7 +19,7 @@ MODULE_PARM_DESC(
1919
2020struct iommufd_attach {
2121 struct iommufd_hw_pagetable * hwpt ;
22- struct list_head device_list ;
22+ struct xarray device_array ;
2323};
2424
2525static void iommufd_group_release (struct kref * kref )
@@ -297,6 +297,20 @@ u32 iommufd_device_to_id(struct iommufd_device *idev)
297297}
298298EXPORT_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
301315static 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 */
372386static 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
382391static 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 ;
547564err_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 );
550569err_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