@@ -396,16 +396,41 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
396
396
return hwpt ;
397
397
}
398
398
399
+ static struct iommufd_hw_pagetable *
400
+ iommufd_device_do_attach (struct iommufd_device * idev ,
401
+ struct iommufd_hw_pagetable * hwpt )
402
+ {
403
+ int rc ;
404
+
405
+ rc = iommufd_hw_pagetable_attach (hwpt , idev );
406
+ if (rc )
407
+ return ERR_PTR (rc );
408
+ return NULL ;
409
+ }
410
+
411
+ typedef struct iommufd_hw_pagetable * (* attach_fn )(
412
+ struct iommufd_device * idev , struct iommufd_hw_pagetable * hwpt );
413
+
399
414
/*
400
415
* When automatically managing the domains we search for a compatible domain in
401
416
* the iopt and if one is found use it, otherwise create a new domain.
402
417
* Automatic domain selection will never pick a manually created domain.
403
418
*/
404
- static int iommufd_device_auto_get_domain (struct iommufd_device * idev ,
405
- struct iommufd_ioas * ioas , u32 * pt_id )
419
+ static struct iommufd_hw_pagetable *
420
+ iommufd_device_auto_get_domain (struct iommufd_device * idev ,
421
+ struct iommufd_ioas * ioas , u32 * pt_id ,
422
+ attach_fn do_attach )
406
423
{
424
+ /*
425
+ * iommufd_hw_pagetable_attach() is called by
426
+ * iommufd_hw_pagetable_alloc() in immediate attachment mode, same as
427
+ * iommufd_device_do_attach(). So if we are in this mode then we prefer
428
+ * to use the immediate_attach path as it supports drivers that can't
429
+ * directly allocate a domain.
430
+ */
431
+ bool immediate_attach = do_attach == iommufd_device_do_attach ;
432
+ struct iommufd_hw_pagetable * destroy_hwpt ;
407
433
struct iommufd_hw_pagetable * hwpt ;
408
- int rc ;
409
434
410
435
/*
411
436
* There is no differentiation when domains are allocated, so any domain
@@ -419,52 +444,58 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
419
444
420
445
if (!iommufd_lock_obj (& hwpt -> obj ))
421
446
continue ;
422
- rc = iommufd_hw_pagetable_attach (hwpt , idev );
423
- iommufd_put_object (& hwpt -> obj );
424
-
425
- /*
426
- * -EINVAL means the domain is incompatible with the device.
427
- * Other error codes should propagate to userspace as failure.
428
- * Success means the domain is attached.
429
- */
430
- if (rc == - EINVAL )
431
- continue ;
447
+ destroy_hwpt = (* do_attach )(idev , hwpt );
448
+ if (IS_ERR (destroy_hwpt )) {
449
+ iommufd_put_object (& hwpt -> obj );
450
+ /*
451
+ * -EINVAL means the domain is incompatible with the
452
+ * device. Other error codes should propagate to
453
+ * userspace as failure. Success means the domain is
454
+ * attached.
455
+ */
456
+ if (PTR_ERR (destroy_hwpt ) == - EINVAL )
457
+ continue ;
458
+ goto out_unlock ;
459
+ }
432
460
* pt_id = hwpt -> obj .id ;
461
+ iommufd_put_object (& hwpt -> obj );
433
462
goto out_unlock ;
434
463
}
435
464
436
- hwpt = iommufd_hw_pagetable_alloc (idev -> ictx , ioas , idev , true);
465
+ hwpt = iommufd_hw_pagetable_alloc (idev -> ictx , ioas , idev ,
466
+ immediate_attach );
437
467
if (IS_ERR (hwpt )) {
438
- rc = PTR_ERR (hwpt );
468
+ destroy_hwpt = ERR_CAST (hwpt );
439
469
goto out_unlock ;
440
470
}
471
+
472
+ if (!immediate_attach ) {
473
+ destroy_hwpt = (* do_attach )(idev , hwpt );
474
+ if (IS_ERR (destroy_hwpt ))
475
+ goto out_abort ;
476
+ } else {
477
+ destroy_hwpt = NULL ;
478
+ }
479
+
441
480
hwpt -> auto_domain = true;
442
481
* pt_id = hwpt -> obj .id ;
443
482
444
483
iommufd_object_finalize (idev -> ictx , & hwpt -> obj );
445
484
mutex_unlock (& ioas -> mutex );
446
- return 0 ;
485
+ return destroy_hwpt ;
486
+
487
+ out_abort :
488
+ iommufd_object_abort_and_destroy (idev -> ictx , & hwpt -> obj );
447
489
out_unlock :
448
490
mutex_unlock (& ioas -> mutex );
449
- return rc ;
491
+ return destroy_hwpt ;
450
492
}
451
493
452
- /**
453
- * iommufd_device_attach - Connect a device from an iommu_domain
454
- * @idev: device to attach
455
- * @pt_id: Input a IOMMUFD_OBJ_IOAS, or IOMMUFD_OBJ_HW_PAGETABLE
456
- * Output the IOMMUFD_OBJ_HW_PAGETABLE ID
457
- *
458
- * This connects the device to an iommu_domain, either automatically or manually
459
- * selected. Once this completes the device could do DMA.
460
- *
461
- * The caller should return the resulting pt_id back to userspace.
462
- * This function is undone by calling iommufd_device_detach().
463
- */
464
- int iommufd_device_attach (struct iommufd_device * idev , u32 * pt_id )
494
+ static int iommufd_device_change_pt (struct iommufd_device * idev , u32 * pt_id ,
495
+ attach_fn do_attach )
465
496
{
497
+ struct iommufd_hw_pagetable * destroy_hwpt ;
466
498
struct iommufd_object * pt_obj ;
467
- int rc ;
468
499
469
500
pt_obj = iommufd_get_object (idev -> ictx , * pt_id , IOMMUFD_OBJ_ANY );
470
501
if (IS_ERR (pt_obj ))
@@ -475,31 +506,63 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)
475
506
struct iommufd_hw_pagetable * hwpt =
476
507
container_of (pt_obj , struct iommufd_hw_pagetable , obj );
477
508
478
- rc = iommufd_hw_pagetable_attach ( hwpt , idev );
479
- if (rc )
509
+ destroy_hwpt = ( * do_attach )( idev , hwpt );
510
+ if (IS_ERR ( destroy_hwpt ) )
480
511
goto out_put_pt_obj ;
481
512
break ;
482
513
}
483
514
case IOMMUFD_OBJ_IOAS : {
484
515
struct iommufd_ioas * ioas =
485
516
container_of (pt_obj , struct iommufd_ioas , obj );
486
517
487
- rc = iommufd_device_auto_get_domain (idev , ioas , pt_id );
488
- if (rc )
518
+ destroy_hwpt = iommufd_device_auto_get_domain (idev , ioas , pt_id ,
519
+ do_attach );
520
+ if (IS_ERR (destroy_hwpt ))
489
521
goto out_put_pt_obj ;
490
522
break ;
491
523
}
492
524
default :
493
- rc = - EINVAL ;
525
+ destroy_hwpt = ERR_PTR ( - EINVAL ) ;
494
526
goto out_put_pt_obj ;
495
527
}
528
+ iommufd_put_object (pt_obj );
496
529
497
- refcount_inc (& idev -> obj .users );
498
- rc = 0 ;
530
+ /* This destruction has to be after we unlock everything */
531
+ if (destroy_hwpt )
532
+ iommufd_hw_pagetable_put (idev -> ictx , destroy_hwpt );
533
+ return 0 ;
499
534
500
535
out_put_pt_obj :
501
536
iommufd_put_object (pt_obj );
502
- return rc ;
537
+ return PTR_ERR (destroy_hwpt );
538
+ }
539
+
540
+ /**
541
+ * iommufd_device_attach - Connect a device to an iommu_domain
542
+ * @idev: device to attach
543
+ * @pt_id: Input a IOMMUFD_OBJ_IOAS, or IOMMUFD_OBJ_HW_PAGETABLE
544
+ * Output the IOMMUFD_OBJ_HW_PAGETABLE ID
545
+ *
546
+ * This connects the device to an iommu_domain, either automatically or manually
547
+ * selected. Once this completes the device could do DMA.
548
+ *
549
+ * The caller should return the resulting pt_id back to userspace.
550
+ * This function is undone by calling iommufd_device_detach().
551
+ */
552
+ int iommufd_device_attach (struct iommufd_device * idev , u32 * pt_id )
553
+ {
554
+ int rc ;
555
+
556
+ rc = iommufd_device_change_pt (idev , pt_id , & iommufd_device_do_attach );
557
+ if (rc )
558
+ return rc ;
559
+
560
+ /*
561
+ * Pairs with iommufd_device_detach() - catches caller bugs attempting
562
+ * to destroy a device with an attachment.
563
+ */
564
+ refcount_inc (& idev -> obj .users );
565
+ return 0 ;
503
566
}
504
567
EXPORT_SYMBOL_NS_GPL (iommufd_device_attach , IOMMUFD );
505
568
0 commit comments