@@ -17,12 +17,17 @@ MODULE_PARM_DESC(
17
17
"Allow IOMMUFD to bind to devices even if the platform cannot isolate "
18
18
"the MSI interrupt window. Enabling this is a security weakness." );
19
19
20
+ struct iommufd_attach {
21
+ struct iommufd_hw_pagetable * hwpt ;
22
+ struct list_head device_list ;
23
+ };
24
+
20
25
static void iommufd_group_release (struct kref * kref )
21
26
{
22
27
struct iommufd_group * igroup =
23
28
container_of (kref , struct iommufd_group , ref );
24
29
25
- WARN_ON (igroup -> hwpt || ! list_empty ( & igroup -> device_list ) );
30
+ WARN_ON (igroup -> attach );
26
31
27
32
xa_cmpxchg (& igroup -> ictx -> groups , iommu_group_id (igroup -> group ), igroup ,
28
33
NULL , GFP_KERNEL );
@@ -89,7 +94,6 @@ static struct iommufd_group *iommufd_get_group(struct iommufd_ctx *ictx,
89
94
90
95
kref_init (& new_igroup -> ref );
91
96
mutex_init (& new_igroup -> lock );
92
- INIT_LIST_HEAD (& new_igroup -> device_list );
93
97
new_igroup -> sw_msi_start = PHYS_ADDR_MAX ;
94
98
/* group reference moves into new_igroup */
95
99
new_igroup -> group = group ;
@@ -333,7 +337,7 @@ static bool
333
337
iommufd_group_first_attach (struct iommufd_group * igroup , ioasid_t pasid )
334
338
{
335
339
lockdep_assert_held (& igroup -> lock );
336
- return !igroup -> hwpt ;
340
+ return !igroup -> attach ;
337
341
}
338
342
339
343
static int
@@ -369,7 +373,7 @@ static bool iommufd_device_is_attached(struct iommufd_device *idev)
369
373
{
370
374
struct iommufd_device * cur ;
371
375
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 )
373
377
if (cur == idev )
374
378
return true;
375
379
return false;
@@ -493,19 +497,33 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
493
497
struct iommufd_hwpt_paging * hwpt_paging = find_hwpt_paging (hwpt );
494
498
bool attach_resv = hwpt_paging && pasid == IOMMU_NO_PASID ;
495
499
struct iommufd_group * igroup = idev -> igroup ;
500
+ struct iommufd_hw_pagetable * old_hwpt ;
501
+ struct iommufd_attach * attach ;
496
502
int rc ;
497
503
498
504
mutex_lock (& igroup -> lock );
499
505
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 ) {
501
519
rc = - EINVAL ;
502
- goto err_unlock ;
520
+ goto err_free_attach ;
503
521
}
504
522
505
523
if (attach_resv ) {
506
524
rc = iommufd_device_attach_reserved_iova (idev , hwpt_paging );
507
525
if (rc )
508
- goto err_unlock ;
526
+ goto err_free_attach ;
509
527
}
510
528
511
529
/*
@@ -519,15 +537,19 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
519
537
rc = iommufd_hwpt_attach_device (hwpt , idev , pasid );
520
538
if (rc )
521
539
goto err_unresv ;
522
- igroup -> hwpt = hwpt ;
540
+ attach -> hwpt = hwpt ;
541
+ igroup -> attach = attach ;
523
542
}
524
543
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 );
526
545
mutex_unlock (& igroup -> lock );
527
546
return 0 ;
528
547
err_unresv :
529
548
if (attach_resv )
530
549
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 );
531
553
err_unlock :
532
554
mutex_unlock (& igroup -> lock );
533
555
return rc ;
@@ -537,14 +559,20 @@ struct iommufd_hw_pagetable *
537
559
iommufd_hw_pagetable_detach (struct iommufd_device * idev , ioasid_t pasid )
538
560
{
539
561
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 ;
542
565
543
566
mutex_lock (& igroup -> lock );
567
+ attach = igroup -> attach ;
568
+ hwpt = attach -> hwpt ;
569
+ hwpt_paging = find_hwpt_paging (hwpt );
570
+
544
571
list_del (& idev -> group_item );
545
- if (list_empty (& igroup -> device_list )) {
572
+ if (list_empty (& attach -> device_list )) {
546
573
iommufd_hwpt_detach_device (hwpt , idev , pasid );
547
- igroup -> hwpt = NULL ;
574
+ igroup -> attach = NULL ;
575
+ kfree (attach );
548
576
}
549
577
if (hwpt_paging && pasid == IOMMU_NO_PASID )
550
578
iopt_remove_reserved_iova (& hwpt_paging -> ioas -> iopt , idev -> dev );
@@ -574,7 +602,7 @@ iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
574
602
575
603
lockdep_assert_held (& igroup -> lock );
576
604
577
- list_for_each_entry (cur , & igroup -> device_list , group_item )
605
+ list_for_each_entry (cur , & igroup -> attach -> device_list , group_item )
578
606
iopt_remove_reserved_iova (& hwpt_paging -> ioas -> iopt , cur -> dev );
579
607
}
580
608
@@ -588,9 +616,10 @@ iommufd_group_do_replace_reserved_iova(struct iommufd_group *igroup,
588
616
589
617
lockdep_assert_held (& igroup -> lock );
590
618
591
- old_hwpt_paging = find_hwpt_paging (igroup -> hwpt );
619
+ old_hwpt_paging = find_hwpt_paging (igroup -> attach -> hwpt );
592
620
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 ) {
594
623
rc = iopt_table_enforce_dev_resv_regions (
595
624
& hwpt_paging -> ioas -> iopt , cur -> dev , NULL );
596
625
if (rc )
@@ -617,27 +646,32 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
617
646
struct iommufd_hwpt_paging * old_hwpt_paging ;
618
647
struct iommufd_group * igroup = idev -> igroup ;
619
648
struct iommufd_hw_pagetable * old_hwpt ;
649
+ struct iommufd_attach * attach ;
620
650
unsigned int num_devices ;
621
651
int rc ;
622
652
623
653
mutex_lock (& igroup -> lock );
624
654
625
- if (igroup -> hwpt == NULL ) {
655
+ attach = igroup -> attach ;
656
+ if (!attach ) {
626
657
rc = - EINVAL ;
627
658
goto err_unlock ;
628
659
}
629
660
661
+ old_hwpt = attach -> hwpt ;
662
+
663
+ WARN_ON (!old_hwpt || list_empty (& attach -> device_list ));
664
+
630
665
if (!iommufd_device_is_attached (idev )) {
631
666
rc = - EINVAL ;
632
667
goto err_unlock ;
633
668
}
634
669
635
- if (hwpt == igroup -> hwpt ) {
670
+ if (hwpt == old_hwpt ) {
636
671
mutex_unlock (& igroup -> lock );
637
672
return NULL ;
638
673
}
639
674
640
- old_hwpt = igroup -> hwpt ;
641
675
if (attach_resv ) {
642
676
rc = iommufd_group_do_replace_reserved_iova (igroup , hwpt_paging );
643
677
if (rc )
@@ -653,9 +687,9 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
653
687
(!hwpt_paging || hwpt_paging -> ioas != old_hwpt_paging -> ioas ))
654
688
iommufd_group_remove_reserved_iova (igroup , old_hwpt_paging );
655
689
656
- igroup -> hwpt = hwpt ;
690
+ attach -> hwpt = hwpt ;
657
691
658
- num_devices = list_count_nodes (& igroup -> device_list );
692
+ num_devices = list_count_nodes (& attach -> device_list );
659
693
/*
660
694
* Move the refcounts held by the device_list to the new hwpt. Retain a
661
695
* refcount for this thread as the caller will free it.
0 commit comments