@@ -15,13 +15,121 @@ MODULE_PARM_DESC(
15
15
"Allow IOMMUFD to bind to devices even if the platform cannot isolate "
16
16
"the MSI interrupt window. Enabling this is a security weakness." );
17
17
18
+ static void iommufd_group_release (struct kref * kref )
19
+ {
20
+ struct iommufd_group * igroup =
21
+ container_of (kref , struct iommufd_group , ref );
22
+
23
+ xa_cmpxchg (& igroup -> ictx -> groups , iommu_group_id (igroup -> group ), igroup ,
24
+ NULL , GFP_KERNEL );
25
+ iommu_group_put (igroup -> group );
26
+ kfree (igroup );
27
+ }
28
+
29
+ static void iommufd_put_group (struct iommufd_group * group )
30
+ {
31
+ kref_put (& group -> ref , iommufd_group_release );
32
+ }
33
+
34
+ static bool iommufd_group_try_get (struct iommufd_group * igroup ,
35
+ struct iommu_group * group )
36
+ {
37
+ if (!igroup )
38
+ return false;
39
+ /*
40
+ * group ID's cannot be re-used until the group is put back which does
41
+ * not happen if we could get an igroup pointer under the xa_lock.
42
+ */
43
+ if (WARN_ON (igroup -> group != group ))
44
+ return false;
45
+ return kref_get_unless_zero (& igroup -> ref );
46
+ }
47
+
48
+ /*
49
+ * iommufd needs to store some more data for each iommu_group, we keep a
50
+ * parallel xarray indexed by iommu_group id to hold this instead of putting it
51
+ * in the core structure. To keep things simple the iommufd_group memory is
52
+ * unique within the iommufd_ctx. This makes it easy to check there are no
53
+ * memory leaks.
54
+ */
55
+ static struct iommufd_group * iommufd_get_group (struct iommufd_ctx * ictx ,
56
+ struct device * dev )
57
+ {
58
+ struct iommufd_group * new_igroup ;
59
+ struct iommufd_group * cur_igroup ;
60
+ struct iommufd_group * igroup ;
61
+ struct iommu_group * group ;
62
+ unsigned int id ;
63
+
64
+ group = iommu_group_get (dev );
65
+ if (!group )
66
+ return ERR_PTR (- ENODEV );
67
+
68
+ id = iommu_group_id (group );
69
+
70
+ xa_lock (& ictx -> groups );
71
+ igroup = xa_load (& ictx -> groups , id );
72
+ if (iommufd_group_try_get (igroup , group )) {
73
+ xa_unlock (& ictx -> groups );
74
+ iommu_group_put (group );
75
+ return igroup ;
76
+ }
77
+ xa_unlock (& ictx -> groups );
78
+
79
+ new_igroup = kzalloc (sizeof (* new_igroup ), GFP_KERNEL );
80
+ if (!new_igroup ) {
81
+ iommu_group_put (group );
82
+ return ERR_PTR (- ENOMEM );
83
+ }
84
+
85
+ kref_init (& new_igroup -> ref );
86
+ /* group reference moves into new_igroup */
87
+ new_igroup -> group = group ;
88
+
89
+ /*
90
+ * The ictx is not additionally refcounted here becase all objects using
91
+ * an igroup must put it before their destroy completes.
92
+ */
93
+ new_igroup -> ictx = ictx ;
94
+
95
+ /*
96
+ * We dropped the lock so igroup is invalid. NULL is a safe and likely
97
+ * value to assume for the xa_cmpxchg algorithm.
98
+ */
99
+ cur_igroup = NULL ;
100
+ xa_lock (& ictx -> groups );
101
+ while (true) {
102
+ igroup = __xa_cmpxchg (& ictx -> groups , id , cur_igroup , new_igroup ,
103
+ GFP_KERNEL );
104
+ if (xa_is_err (igroup )) {
105
+ xa_unlock (& ictx -> groups );
106
+ iommufd_put_group (new_igroup );
107
+ return ERR_PTR (xa_err (igroup ));
108
+ }
109
+
110
+ /* new_group was successfully installed */
111
+ if (cur_igroup == igroup ) {
112
+ xa_unlock (& ictx -> groups );
113
+ return new_igroup ;
114
+ }
115
+
116
+ /* Check again if the current group is any good */
117
+ if (iommufd_group_try_get (igroup , group )) {
118
+ xa_unlock (& ictx -> groups );
119
+ iommufd_put_group (new_igroup );
120
+ return igroup ;
121
+ }
122
+ cur_igroup = igroup ;
123
+ }
124
+ }
125
+
18
126
void iommufd_device_destroy (struct iommufd_object * obj )
19
127
{
20
128
struct iommufd_device * idev =
21
129
container_of (obj , struct iommufd_device , obj );
22
130
23
131
iommu_device_release_dma_owner (idev -> dev );
24
- iommu_group_put (idev -> group );
132
+ iommufd_put_group (idev -> igroup );
25
133
if (!iommufd_selftest_is_mock_dev (idev -> dev ))
26
134
iommufd_ctx_put (idev -> ictx );
27
135
}
@@ -46,7 +154,7 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
46
154
struct device * dev , u32 * id )
47
155
{
48
156
struct iommufd_device * idev ;
49
- struct iommu_group * group ;
157
+ struct iommufd_group * igroup ;
50
158
int rc ;
51
159
52
160
/*
@@ -56,9 +164,9 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
56
164
if (!device_iommu_capable (dev , IOMMU_CAP_CACHE_COHERENCY ))
57
165
return ERR_PTR (- EINVAL );
58
166
59
- group = iommu_group_get ( dev );
60
- if (! group )
61
- return ERR_PTR ( - ENODEV );
167
+ igroup = iommufd_get_group ( ictx , dev );
168
+ if (IS_ERR ( igroup ) )
169
+ return ERR_CAST ( igroup );
62
170
63
171
/*
64
172
* For historical compat with VFIO the insecure interrupt path is
@@ -67,7 +175,7 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
67
175
* interrupt outside this iommufd context.
68
176
*/
69
177
if (!iommufd_selftest_is_mock_dev (dev ) &&
70
- !iommu_group_has_isolated_msi (group )) {
178
+ !iommu_group_has_isolated_msi (igroup -> group )) {
71
179
if (!allow_unsafe_interrupts ) {
72
180
rc = - EPERM ;
73
181
goto out_group_put ;
@@ -97,8 +205,8 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
97
205
device_iommu_capable (dev , IOMMU_CAP_ENFORCE_CACHE_COHERENCY );
98
206
/* The calling driver is a user until iommufd_device_unbind() */
99
207
refcount_inc (& idev -> obj .users );
100
- /* group refcount moves into iommufd_device */
101
- idev -> group = group ;
208
+ /* igroup refcount moves into iommufd_device */
209
+ idev -> igroup = igroup ;
102
210
103
211
/*
104
212
* If the caller fails after this success it must call
@@ -113,7 +221,7 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
113
221
out_release_owner :
114
222
iommu_device_release_dma_owner (dev );
115
223
out_group_put :
116
- iommu_group_put ( group );
224
+ iommufd_put_group ( igroup );
117
225
return ERR_PTR (rc );
118
226
}
119
227
EXPORT_SYMBOL_NS_GPL (iommufd_device_bind , IOMMUFD );
@@ -138,7 +246,8 @@ bool iommufd_ctx_has_group(struct iommufd_ctx *ictx, struct iommu_group *group)
138
246
xa_lock (& ictx -> objects );
139
247
xa_for_each (& ictx -> objects , index , obj ) {
140
248
if (obj -> type == IOMMUFD_OBJ_DEVICE &&
141
- container_of (obj , struct iommufd_device , obj )-> group == group ) {
249
+ container_of (obj , struct iommufd_device , obj )
250
+ -> igroup -> group == group ) {
142
251
xa_unlock (& ictx -> objects );
143
252
return true;
144
253
}
@@ -212,14 +321,14 @@ static int iommufd_device_setup_msi(struct iommufd_device *idev,
212
321
}
213
322
214
323
static bool iommufd_hw_pagetable_has_group (struct iommufd_hw_pagetable * hwpt ,
215
- struct iommu_group * group )
324
+ struct iommufd_group * igroup )
216
325
{
217
326
struct iommufd_device * cur_dev ;
218
327
219
328
lockdep_assert_held (& hwpt -> devices_lock );
220
329
221
330
list_for_each_entry (cur_dev , & hwpt -> devices , devices_item )
222
- if (cur_dev -> group == group )
331
+ if (cur_dev -> igroup -> group == igroup -> group )
223
332
return true;
224
333
return false;
225
334
}
@@ -253,7 +362,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
253
362
}
254
363
255
364
rc = iopt_table_enforce_group_resv_regions (& hwpt -> ioas -> iopt , idev -> dev ,
256
- idev -> group , & sw_msi_start );
365
+ idev -> igroup -> group ,
366
+ & sw_msi_start );
257
367
if (rc )
258
368
return rc ;
259
369
@@ -265,8 +375,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
265
375
* FIXME: Hack around missing a device-centric iommu api, only attach to
266
376
* the group once for the first device that is in the group.
267
377
*/
268
- if (!iommufd_hw_pagetable_has_group (hwpt , idev -> group )) {
269
- rc = iommu_attach_group (hwpt -> domain , idev -> group );
378
+ if (!iommufd_hw_pagetable_has_group (hwpt , idev -> igroup )) {
379
+ rc = iommu_attach_group (hwpt -> domain , idev -> igroup -> group );
270
380
if (rc )
271
381
goto err_unresv ;
272
382
}
@@ -279,8 +389,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
279
389
void iommufd_hw_pagetable_detach (struct iommufd_hw_pagetable * hwpt ,
280
390
struct iommufd_device * idev )
281
391
{
282
- if (!iommufd_hw_pagetable_has_group (hwpt , idev -> group ))
283
- iommu_detach_group (hwpt -> domain , idev -> group );
392
+ if (!iommufd_hw_pagetable_has_group (hwpt , idev -> igroup ))
393
+ iommu_detach_group (hwpt -> domain , idev -> igroup -> group );
284
394
iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
285
395
}
286
396
0 commit comments