@@ -228,13 +228,27 @@ static void destroy_unused_implicit_child_mr(struct mlx5_ib_mr *mr)
228
228
unsigned long idx = ib_umem_start (odp ) >> MLX5_IMR_MTT_SHIFT ;
229
229
struct mlx5_ib_mr * imr = mr -> parent ;
230
230
231
+ /*
232
+ * If userspace is racing freeing the parent implicit ODP MR then we can
233
+ * loose the race with parent destruction. In this case
234
+ * mlx5_ib_free_odp_mr() will free everything in the implicit_children
235
+ * xarray so NOP is fine. This child MR cannot be destroyed here because
236
+ * we are under its umem_mutex.
237
+ */
231
238
if (!refcount_inc_not_zero (& imr -> mmkey .usecount ))
232
239
return ;
233
240
234
- xa_erase (& imr -> implicit_children , idx );
241
+ xa_lock (& imr -> implicit_children );
242
+ if (__xa_cmpxchg (& imr -> implicit_children , idx , mr , NULL , GFP_KERNEL ) !=
243
+ mr ) {
244
+ xa_unlock (& imr -> implicit_children );
245
+ return ;
246
+ }
247
+
235
248
if (MLX5_CAP_ODP (mr_to_mdev (mr )-> mdev , mem_page_fault ))
236
- xa_erase (& mr_to_mdev (mr )-> odp_mkeys ,
237
- mlx5_base_mkey (mr -> mmkey .key ));
249
+ __xa_erase (& mr_to_mdev (mr )-> odp_mkeys ,
250
+ mlx5_base_mkey (mr -> mmkey .key ));
251
+ xa_unlock (& imr -> implicit_children );
238
252
239
253
/* Freeing a MR is a sleeping operation, so bounce to a work queue */
240
254
INIT_WORK (& mr -> odp_destroy .work , free_implicit_child_mr_work );
@@ -502,18 +516,18 @@ static struct mlx5_ib_mr *implicit_get_child_mr(struct mlx5_ib_mr *imr,
502
516
refcount_inc (& ret -> mmkey .usecount );
503
517
goto out_lock ;
504
518
}
505
- xa_unlock (& imr -> implicit_children );
506
519
507
520
if (MLX5_CAP_ODP (dev -> mdev , mem_page_fault )) {
508
- ret = xa_store (& dev -> odp_mkeys , mlx5_base_mkey (mr -> mmkey .key ),
509
- & mr -> mmkey , GFP_KERNEL );
521
+ ret = __xa_store (& dev -> odp_mkeys , mlx5_base_mkey (mr -> mmkey .key ),
522
+ & mr -> mmkey , GFP_KERNEL );
510
523
if (xa_is_err (ret )) {
511
524
ret = ERR_PTR (xa_err (ret ));
512
- xa_erase (& imr -> implicit_children , idx );
513
- goto out_mr ;
525
+ __xa_erase (& imr -> implicit_children , idx );
526
+ goto out_lock ;
514
527
}
515
528
mr -> mmkey .type = MLX5_MKEY_IMPLICIT_CHILD ;
516
529
}
530
+ xa_unlock (& imr -> implicit_children );
517
531
mlx5_ib_dbg (mr_to_mdev (imr ), "key %x mr %p\n" , mr -> mmkey .key , mr );
518
532
return mr ;
519
533
0 commit comments