@@ -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 );
@@ -500,18 +514,18 @@ static struct mlx5_ib_mr *implicit_get_child_mr(struct mlx5_ib_mr *imr,
500
514
refcount_inc (& ret -> mmkey .usecount );
501
515
goto out_lock ;
502
516
}
503
- xa_unlock (& imr -> implicit_children );
504
517
505
518
if (MLX5_CAP_ODP (dev -> mdev , mem_page_fault )) {
506
- ret = xa_store (& dev -> odp_mkeys , mlx5_base_mkey (mr -> mmkey .key ),
507
- & mr -> mmkey , GFP_KERNEL );
519
+ ret = __xa_store (& dev -> odp_mkeys , mlx5_base_mkey (mr -> mmkey .key ),
520
+ & mr -> mmkey , GFP_KERNEL );
508
521
if (xa_is_err (ret )) {
509
522
ret = ERR_PTR (xa_err (ret ));
510
- xa_erase (& imr -> implicit_children , idx );
511
- goto out_mr ;
523
+ __xa_erase (& imr -> implicit_children , idx );
524
+ goto out_lock ;
512
525
}
513
526
mr -> mmkey .type = MLX5_MKEY_IMPLICIT_CHILD ;
514
527
}
528
+ xa_unlock (& imr -> implicit_children );
515
529
mlx5_ib_dbg (mr_to_mdev (imr ), "key %x mr %p\n" , mr -> mmkey .key , mr );
516
530
return mr ;
517
531
0 commit comments