@@ -15,31 +15,15 @@ MODULE_PARM_DESC(
1515 "Allow IOMMUFD to bind to devices even if the platform cannot isolate "
1616 "the MSI interrupt window. Enabling this is a security weakness." );
1717
18- /*
19- * A iommufd_device object represents the binding relationship between a
20- * consuming driver and the iommufd. These objects are created/destroyed by
21- * external drivers, not by userspace.
22- */
23- struct iommufd_device {
24- struct iommufd_object obj ;
25- struct iommufd_ctx * ictx ;
26- struct iommufd_hw_pagetable * hwpt ;
27- /* Head at iommufd_hw_pagetable::devices */
28- struct list_head devices_item ;
29- /* always the physical device */
30- struct device * dev ;
31- struct iommu_group * group ;
32- bool enforce_cache_coherency ;
33- };
34-
3518void iommufd_device_destroy (struct iommufd_object * obj )
3619{
3720 struct iommufd_device * idev =
3821 container_of (obj , struct iommufd_device , obj );
3922
4023 iommu_device_release_dma_owner (idev -> dev );
4124 iommu_group_put (idev -> group );
42- iommufd_ctx_put (idev -> ictx );
25+ if (!iommufd_selftest_is_mock_dev (idev -> dev ))
26+ iommufd_ctx_put (idev -> ictx );
4327}
4428
4529/**
@@ -86,7 +70,8 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
8670 goto out_release_owner ;
8771 }
8872 idev -> ictx = ictx ;
89- iommufd_ctx_get (ictx );
73+ if (!iommufd_selftest_is_mock_dev (dev ))
74+ iommufd_ctx_get (ictx );
9075 idev -> dev = dev ;
9176 idev -> enforce_cache_coherency =
9277 device_iommu_capable (dev , IOMMU_CAP_ENFORCE_CACHE_COHERENCY );
@@ -168,7 +153,8 @@ static int iommufd_device_setup_msi(struct iommufd_device *idev,
168153 * operation from the device (eg a simple DMA) cannot trigger an
169154 * interrupt outside this iommufd context.
170155 */
171- if (!iommu_group_has_isolated_msi (idev -> group )) {
156+ if (!iommufd_selftest_is_mock_dev (idev -> dev ) &&
157+ !iommu_group_has_isolated_msi (idev -> group )) {
172158 if (!allow_unsafe_interrupts )
173159 return - EPERM ;
174160
@@ -186,19 +172,24 @@ static bool iommufd_hw_pagetable_has_group(struct iommufd_hw_pagetable *hwpt,
186172{
187173 struct iommufd_device * cur_dev ;
188174
175+ lockdep_assert_held (& hwpt -> devices_lock );
176+
189177 list_for_each_entry (cur_dev , & hwpt -> devices , devices_item )
190178 if (cur_dev -> group == group )
191179 return true;
192180 return false;
193181}
194182
195- static int iommufd_device_do_attach (struct iommufd_device * idev ,
196- struct iommufd_hw_pagetable * hwpt )
183+ int iommufd_hw_pagetable_attach (struct iommufd_hw_pagetable * hwpt ,
184+ struct iommufd_device * idev )
197185{
198186 phys_addr_t sw_msi_start = PHYS_ADDR_MAX ;
199187 int rc ;
200188
201- mutex_lock (& hwpt -> devices_lock );
189+ lockdep_assert_held (& hwpt -> devices_lock );
190+
191+ if (WARN_ON (idev -> hwpt ))
192+ return - EINVAL ;
202193
203194 /*
204195 * Try to upgrade the domain we have, it is an iommu driver bug to
@@ -213,19 +204,18 @@ static int iommufd_device_do_attach(struct iommufd_device *idev,
213204 hwpt -> domain );
214205 if (!hwpt -> enforce_cache_coherency ) {
215206 WARN_ON (list_empty (& hwpt -> devices ));
216- rc = - EINVAL ;
217- goto out_unlock ;
207+ return - EINVAL ;
218208 }
219209 }
220210
221211 rc = iopt_table_enforce_group_resv_regions (& hwpt -> ioas -> iopt , idev -> dev ,
222212 idev -> group , & sw_msi_start );
223213 if (rc )
224- goto out_unlock ;
214+ return rc ;
225215
226216 rc = iommufd_device_setup_msi (idev , hwpt , sw_msi_start );
227217 if (rc )
228- goto out_iova ;
218+ goto err_unresv ;
229219
230220 /*
231221 * FIXME: Hack around missing a device-centric iommu api, only attach to
@@ -234,26 +224,35 @@ static int iommufd_device_do_attach(struct iommufd_device *idev,
234224 if (!iommufd_hw_pagetable_has_group (hwpt , idev -> group )) {
235225 rc = iommu_attach_group (hwpt -> domain , idev -> group );
236226 if (rc )
237- goto out_iova ;
238-
239- if (list_empty (& hwpt -> devices )) {
240- rc = iopt_table_add_domain (& hwpt -> ioas -> iopt ,
241- hwpt -> domain );
242- if (rc )
243- goto out_detach ;
244- }
227+ goto err_unresv ;
245228 }
229+ return 0 ;
230+ err_unresv :
231+ iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
232+ return rc ;
233+ }
234+
235+ void iommufd_hw_pagetable_detach (struct iommufd_hw_pagetable * hwpt ,
236+ struct iommufd_device * idev )
237+ {
238+ if (!iommufd_hw_pagetable_has_group (hwpt , idev -> group ))
239+ iommu_detach_group (hwpt -> domain , idev -> group );
240+ iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
241+ }
242+
243+ static int iommufd_device_do_attach (struct iommufd_device * idev ,
244+ struct iommufd_hw_pagetable * hwpt )
245+ {
246+ int rc ;
247+
248+ mutex_lock (& hwpt -> devices_lock );
249+ rc = iommufd_hw_pagetable_attach (hwpt , idev );
250+ if (rc )
251+ goto out_unlock ;
246252
247253 idev -> hwpt = hwpt ;
248254 refcount_inc (& hwpt -> obj .users );
249255 list_add (& idev -> devices_item , & hwpt -> devices );
250- mutex_unlock (& hwpt -> devices_lock );
251- return 0 ;
252-
253- out_detach :
254- iommu_detach_group (hwpt -> domain , idev -> group );
255- out_iova :
256- iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
257256out_unlock :
258257 mutex_unlock (& hwpt -> devices_lock );
259258 return rc ;
@@ -280,7 +279,10 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
280279 if (!hwpt -> auto_domain )
281280 continue ;
282281
282+ if (!iommufd_lock_obj (& hwpt -> obj ))
283+ continue ;
283284 rc = iommufd_device_do_attach (idev , hwpt );
285+ iommufd_put_object (& hwpt -> obj );
284286
285287 /*
286288 * -EINVAL means the domain is incompatible with the device.
@@ -292,24 +294,16 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
292294 goto out_unlock ;
293295 }
294296
295- hwpt = iommufd_hw_pagetable_alloc (idev -> ictx , ioas , idev -> dev );
297+ hwpt = iommufd_hw_pagetable_alloc (idev -> ictx , ioas , idev , true );
296298 if (IS_ERR (hwpt )) {
297299 rc = PTR_ERR (hwpt );
298300 goto out_unlock ;
299301 }
300302 hwpt -> auto_domain = true;
301303
302- rc = iommufd_device_do_attach (idev , hwpt );
303- if (rc )
304- goto out_abort ;
305- list_add_tail (& hwpt -> hwpt_item , & ioas -> hwpt_list );
306-
307304 mutex_unlock (& ioas -> mutex );
308305 iommufd_object_finalize (idev -> ictx , & hwpt -> obj );
309306 return 0 ;
310-
311- out_abort :
312- iommufd_object_abort_and_destroy (idev -> ictx , & hwpt -> obj );
313307out_unlock :
314308 mutex_unlock (& ioas -> mutex );
315309 return rc ;
@@ -381,28 +375,17 @@ void iommufd_device_detach(struct iommufd_device *idev)
381375{
382376 struct iommufd_hw_pagetable * hwpt = idev -> hwpt ;
383377
384- mutex_lock (& hwpt -> ioas -> mutex );
385378 mutex_lock (& hwpt -> devices_lock );
386379 list_del (& idev -> devices_item );
387- if (!iommufd_hw_pagetable_has_group (hwpt , idev -> group )) {
388- if (list_empty (& hwpt -> devices )) {
389- iopt_table_remove_domain (& hwpt -> ioas -> iopt ,
390- hwpt -> domain );
391- list_del (& hwpt -> hwpt_item );
392- }
393- iommu_detach_group (hwpt -> domain , idev -> group );
394- }
395- iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
380+ idev -> hwpt = NULL ;
381+ iommufd_hw_pagetable_detach (hwpt , idev );
396382 mutex_unlock (& hwpt -> devices_lock );
397- mutex_unlock (& hwpt -> ioas -> mutex );
398383
399384 if (hwpt -> auto_domain )
400385 iommufd_object_destroy_user (idev -> ictx , & hwpt -> obj );
401386 else
402387 refcount_dec (& hwpt -> obj .users );
403388
404- idev -> hwpt = NULL ;
405-
406389 refcount_dec (& idev -> obj .users );
407390}
408391EXPORT_SYMBOL_NS_GPL (iommufd_device_detach , IOMMUFD );
@@ -412,17 +395,20 @@ void iommufd_access_destroy_object(struct iommufd_object *obj)
412395 struct iommufd_access * access =
413396 container_of (obj , struct iommufd_access , obj );
414397
415- iopt_remove_access (& access -> ioas -> iopt , access );
398+ if (access -> ioas ) {
399+ iopt_remove_access (& access -> ioas -> iopt , access );
400+ refcount_dec (& access -> ioas -> obj .users );
401+ access -> ioas = NULL ;
402+ }
416403 iommufd_ctx_put (access -> ictx );
417- refcount_dec (& access -> ioas -> obj .users );
418404}
419405
420406/**
421407 * iommufd_access_create - Create an iommufd_access
422408 * @ictx: iommufd file descriptor
423- * @ioas_id: ID for a IOMMUFD_OBJ_IOAS
424409 * @ops: Driver's ops to associate with the access
425410 * @data: Opaque data to pass into ops functions
411+ * @id: Output ID number to return to userspace for this access
426412 *
427413 * An iommufd_access allows a driver to read/write to the IOAS without using
428414 * DMA. The underlying CPU memory can be accessed using the
@@ -431,12 +417,10 @@ void iommufd_access_destroy_object(struct iommufd_object *obj)
431417 * The provided ops are required to use iommufd_access_pin_pages().
432418 */
433419struct iommufd_access *
434- iommufd_access_create (struct iommufd_ctx * ictx , u32 ioas_id ,
435- const struct iommufd_access_ops * ops , void * data )
420+ iommufd_access_create (struct iommufd_ctx * ictx ,
421+ const struct iommufd_access_ops * ops , void * data , u32 * id )
436422{
437423 struct iommufd_access * access ;
438- struct iommufd_object * obj ;
439- int rc ;
440424
441425 /*
442426 * There is no uAPI for the access object, but to keep things symmetric
@@ -449,33 +433,18 @@ iommufd_access_create(struct iommufd_ctx *ictx, u32 ioas_id,
449433 access -> data = data ;
450434 access -> ops = ops ;
451435
452- obj = iommufd_get_object (ictx , ioas_id , IOMMUFD_OBJ_IOAS );
453- if (IS_ERR (obj )) {
454- rc = PTR_ERR (obj );
455- goto out_abort ;
456- }
457- access -> ioas = container_of (obj , struct iommufd_ioas , obj );
458- iommufd_ref_to_users (obj );
459-
460436 if (ops -> needs_pin_pages )
461437 access -> iova_alignment = PAGE_SIZE ;
462438 else
463439 access -> iova_alignment = 1 ;
464- rc = iopt_add_access (& access -> ioas -> iopt , access );
465- if (rc )
466- goto out_put_ioas ;
467440
468441 /* The calling driver is a user until iommufd_access_destroy() */
469442 refcount_inc (& access -> obj .users );
470443 access -> ictx = ictx ;
471444 iommufd_ctx_get (ictx );
472445 iommufd_object_finalize (ictx , & access -> obj );
446+ * id = access -> obj .id ;
473447 return access ;
474- out_put_ioas :
475- refcount_dec (& access -> ioas -> obj .users );
476- out_abort :
477- iommufd_object_abort (ictx , & access -> obj );
478- return ERR_PTR (rc );
479448}
480449EXPORT_SYMBOL_NS_GPL (iommufd_access_create , IOMMUFD );
481450
@@ -494,6 +463,30 @@ void iommufd_access_destroy(struct iommufd_access *access)
494463}
495464EXPORT_SYMBOL_NS_GPL (iommufd_access_destroy , IOMMUFD );
496465
466+ int iommufd_access_attach (struct iommufd_access * access , u32 ioas_id )
467+ {
468+ struct iommufd_ioas * new_ioas ;
469+ int rc = 0 ;
470+
471+ if (access -> ioas )
472+ return - EINVAL ;
473+
474+ new_ioas = iommufd_get_ioas (access -> ictx , ioas_id );
475+ if (IS_ERR (new_ioas ))
476+ return PTR_ERR (new_ioas );
477+
478+ rc = iopt_add_access (& new_ioas -> iopt , access );
479+ if (rc ) {
480+ iommufd_put_object (& new_ioas -> obj );
481+ return rc ;
482+ }
483+ iommufd_ref_to_users (& new_ioas -> obj );
484+
485+ access -> ioas = new_ioas ;
486+ return 0 ;
487+ }
488+ EXPORT_SYMBOL_NS_GPL (iommufd_access_attach , IOMMUFD );
489+
497490/**
498491 * iommufd_access_notify_unmap - Notify users of an iopt to stop using it
499492 * @iopt: iopt to work on
@@ -726,41 +719,3 @@ int iommufd_access_rw(struct iommufd_access *access, unsigned long iova,
726719 return rc ;
727720}
728721EXPORT_SYMBOL_NS_GPL (iommufd_access_rw , IOMMUFD );
729-
730- #ifdef CONFIG_IOMMUFD_TEST
731- /*
732- * Creating a real iommufd_device is too hard, bypass creating a iommufd_device
733- * and go directly to attaching a domain.
734- */
735- struct iommufd_hw_pagetable *
736- iommufd_device_selftest_attach (struct iommufd_ctx * ictx ,
737- struct iommufd_ioas * ioas ,
738- struct device * mock_dev )
739- {
740- struct iommufd_hw_pagetable * hwpt ;
741- int rc ;
742-
743- hwpt = iommufd_hw_pagetable_alloc (ictx , ioas , mock_dev );
744- if (IS_ERR (hwpt ))
745- return hwpt ;
746-
747- rc = iopt_table_add_domain (& hwpt -> ioas -> iopt , hwpt -> domain );
748- if (rc )
749- goto out_hwpt ;
750-
751- refcount_inc (& hwpt -> obj .users );
752- iommufd_object_finalize (ictx , & hwpt -> obj );
753- return hwpt ;
754-
755- out_hwpt :
756- iommufd_object_abort_and_destroy (ictx , & hwpt -> obj );
757- return ERR_PTR (rc );
758- }
759-
760- void iommufd_device_selftest_detach (struct iommufd_ctx * ictx ,
761- struct iommufd_hw_pagetable * hwpt )
762- {
763- iopt_table_remove_domain (& hwpt -> ioas -> iopt , hwpt -> domain );
764- refcount_dec (& hwpt -> obj .users );
765- }
766- #endif
0 commit comments