@@ -21,7 +21,7 @@ struct i915_mm_struct {
21
21
struct i915_mmu_notifier * mn ;
22
22
struct hlist_node node ;
23
23
struct kref kref ;
24
- struct work_struct work ;
24
+ struct rcu_work work ;
25
25
};
26
26
27
27
#if defined(CONFIG_MMU_NOTIFIER )
@@ -189,40 +189,31 @@ i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj)
189
189
static struct i915_mmu_notifier *
190
190
i915_mmu_notifier_find (struct i915_mm_struct * mm )
191
191
{
192
- struct i915_mmu_notifier * mn ;
193
- int err = 0 ;
192
+ struct i915_mmu_notifier * mn , * old ;
193
+ int err ;
194
194
195
- mn = mm -> mn ;
196
- if (mn )
195
+ mn = READ_ONCE ( mm -> mn ) ;
196
+ if (likely ( mn ) )
197
197
return mn ;
198
198
199
199
mn = i915_mmu_notifier_create (mm );
200
200
if (IS_ERR (mn ))
201
- err = PTR_ERR (mn );
202
-
203
- mmap_write_lock (mm -> mm );
204
- mutex_lock (& mm -> i915 -> mm_lock );
205
- if (mm -> mn == NULL && !err ) {
206
- /* Protected by mmap_lock (write-lock) */
207
- err = __mmu_notifier_register (& mn -> mn , mm -> mm );
208
- if (!err ) {
209
- /* Protected by mm_lock */
210
- mm -> mn = fetch_and_zero (& mn );
211
- }
212
- } else if (mm -> mn ) {
213
- /*
214
- * Someone else raced and successfully installed the mmu
215
- * notifier, we can cancel our own errors.
216
- */
217
- err = 0 ;
201
+ return mn ;
202
+
203
+ err = mmu_notifier_register (& mn -> mn , mm -> mm );
204
+ if (err ) {
205
+ kfree (mn );
206
+ return ERR_PTR (err );
218
207
}
219
- mutex_unlock (& mm -> i915 -> mm_lock );
220
- mmap_write_unlock (mm -> mm );
221
208
222
- if (mn && !IS_ERR (mn ))
209
+ old = cmpxchg (& mm -> mn , NULL , mn );
210
+ if (old ) {
211
+ mmu_notifier_unregister (& mn -> mn , mm -> mm );
223
212
kfree (mn );
213
+ mn = old ;
214
+ }
224
215
225
- return err ? ERR_PTR ( err ) : mm -> mn ;
216
+ return mn ;
226
217
}
227
218
228
219
static int
@@ -301,23 +292,28 @@ i915_mmu_notifier_free(struct i915_mmu_notifier *mn,
301
292
#endif
302
293
303
294
static struct i915_mm_struct *
304
- __i915_mm_struct_find (struct drm_i915_private * dev_priv , struct mm_struct * real )
295
+ __i915_mm_struct_find (struct drm_i915_private * i915 , struct mm_struct * real )
305
296
{
306
- struct i915_mm_struct * mm ;
307
-
308
- /* Protected by dev_priv->mm_lock */
309
- hash_for_each_possible (dev_priv -> mm_structs , mm , node , (unsigned long )real )
310
- if (mm -> mm == real )
311
- return mm ;
297
+ struct i915_mm_struct * it , * mm = NULL ;
298
+
299
+ rcu_read_lock ();
300
+ hash_for_each_possible_rcu (i915 -> mm_structs ,
301
+ it , node ,
302
+ (unsigned long )real )
303
+ if (it -> mm == real && kref_get_unless_zero (& it -> kref )) {
304
+ mm = it ;
305
+ break ;
306
+ }
307
+ rcu_read_unlock ();
312
308
313
- return NULL ;
309
+ return mm ;
314
310
}
315
311
316
312
static int
317
313
i915_gem_userptr_init__mm_struct (struct drm_i915_gem_object * obj )
318
314
{
319
- struct drm_i915_private * dev_priv = to_i915 (obj -> base .dev );
320
- struct i915_mm_struct * mm ;
315
+ struct drm_i915_private * i915 = to_i915 (obj -> base .dev );
316
+ struct i915_mm_struct * mm , * new ;
321
317
int ret = 0 ;
322
318
323
319
/* During release of the GEM object we hold the struct_mutex. This
@@ -330,39 +326,42 @@ i915_gem_userptr_init__mm_struct(struct drm_i915_gem_object *obj)
330
326
* struct_mutex, i.e. we need to schedule a worker to do the clean
331
327
* up.
332
328
*/
333
- mutex_lock (& dev_priv -> mm_lock );
334
- mm = __i915_mm_struct_find (dev_priv , current -> mm );
335
- if (mm == NULL ) {
336
- mm = kmalloc (sizeof (* mm ), GFP_KERNEL );
337
- if (mm == NULL ) {
338
- ret = - ENOMEM ;
339
- goto out ;
340
- }
329
+ mm = __i915_mm_struct_find (i915 , current -> mm );
330
+ if (mm )
331
+ goto out ;
341
332
342
- kref_init (& mm -> kref );
343
- mm -> i915 = to_i915 (obj -> base .dev );
333
+ new = kmalloc (sizeof (* mm ), GFP_KERNEL );
334
+ if (!new )
335
+ return - ENOMEM ;
344
336
345
- mm -> mm = current -> mm ;
337
+ kref_init (& new -> kref );
338
+ new -> i915 = to_i915 (obj -> base .dev );
339
+ new -> mm = current -> mm ;
340
+ new -> mn = NULL ;
341
+
342
+ spin_lock (& i915 -> mm_lock );
343
+ mm = __i915_mm_struct_find (i915 , current -> mm );
344
+ if (!mm ) {
345
+ hash_add_rcu (i915 -> mm_structs ,
346
+ & new -> node ,
347
+ (unsigned long )new -> mm );
346
348
mmgrab (current -> mm );
349
+ mm = new ;
350
+ }
351
+ spin_unlock (& i915 -> mm_lock );
352
+ if (mm != new )
353
+ kfree (new );
347
354
348
- mm -> mn = NULL ;
349
-
350
- /* Protected by dev_priv->mm_lock */
351
- hash_add (dev_priv -> mm_structs ,
352
- & mm -> node , (unsigned long )mm -> mm );
353
- } else
354
- kref_get (& mm -> kref );
355
-
356
- obj -> userptr .mm = mm ;
357
355
out :
358
- mutex_unlock ( & dev_priv -> mm_lock ) ;
356
+ obj -> userptr . mm = mm ;
359
357
return ret ;
360
358
}
361
359
362
360
static void
363
361
__i915_mm_struct_free__worker (struct work_struct * work )
364
362
{
365
- struct i915_mm_struct * mm = container_of (work , typeof (* mm ), work );
363
+ struct i915_mm_struct * mm = container_of (work , typeof (* mm ), work .work );
364
+
366
365
i915_mmu_notifier_free (mm -> mn , mm -> mm );
367
366
mmdrop (mm -> mm );
368
367
kfree (mm );
@@ -373,12 +372,12 @@ __i915_mm_struct_free(struct kref *kref)
373
372
{
374
373
struct i915_mm_struct * mm = container_of (kref , typeof (* mm ), kref );
375
374
376
- /* Protected by dev_priv-> mm_lock */
377
- hash_del (& mm -> node );
378
- mutex_unlock (& mm -> i915 -> mm_lock );
375
+ spin_lock ( & mm -> i915 -> mm_lock );
376
+ hash_del_rcu (& mm -> node );
377
+ spin_unlock (& mm -> i915 -> mm_lock );
379
378
380
- INIT_WORK (& mm -> work , __i915_mm_struct_free__worker );
381
- queue_work ( mm -> i915 -> mm . userptr_wq , & mm -> work );
379
+ INIT_RCU_WORK (& mm -> work , __i915_mm_struct_free__worker );
380
+ queue_rcu_work ( system_wq , & mm -> work );
382
381
}
383
382
384
383
static void
@@ -387,9 +386,7 @@ i915_gem_userptr_release__mm_struct(struct drm_i915_gem_object *obj)
387
386
if (obj -> userptr .mm == NULL )
388
387
return ;
389
388
390
- kref_put_mutex (& obj -> userptr .mm -> kref ,
391
- __i915_mm_struct_free ,
392
- & to_i915 (obj -> base .dev )-> mm_lock );
389
+ kref_put (& obj -> userptr .mm -> kref , __i915_mm_struct_free );
393
390
obj -> userptr .mm = NULL ;
394
391
}
395
392
@@ -851,7 +848,7 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
851
848
852
849
int i915_gem_init_userptr (struct drm_i915_private * dev_priv )
853
850
{
854
- mutex_init (& dev_priv -> mm_lock );
851
+ spin_lock_init (& dev_priv -> mm_lock );
855
852
hash_init (dev_priv -> mm_structs );
856
853
857
854
dev_priv -> mm .userptr_wq =
0 commit comments