Skip to content

Commit

Permalink
RDMA/mlx5: Consolidate MR destruction to mlx5_ib_dereg_mr()
Browse files Browse the repository at this point in the history
Now that the SRCU stuff has been removed the entire MR destroy logic can
be made a lot simpler. Currently there are many different ways to destroy a
MR and it makes it really hard to do this task correctly. Route all
destruction through mlx5_ib_dereg_mr() and make it work for all
situations.

Since it turns out all the different MR types do basically the same thing
this removes a lot of knowledge of MR internals from ODP and leaves ODP
just exporting an operation to clean up children.

This fixes a few weird corner cases bugs and firmly uses the correct
ordering of the MR destruction:
 - Stop parallel access to the mkey via the ODP xarray
 - Stop DMA
 - Release the umem
 - Clean up ODP children
 - Free/Recycle the MR

Link: https://lore.kernel.org/r/20210304120745.1090751-4-leon@kernel.org
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
  • Loading branch information
jgunthorpe committed Mar 12, 2021
1 parent f18ec42 commit e6fb246
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 203 deletions.
4 changes: 4 additions & 0 deletions drivers/infiniband/core/umem_dmabuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf)
{
struct dma_buf *dmabuf = umem_dmabuf->attach->dmabuf;

dma_resv_lock(dmabuf->resv, NULL);
ib_umem_dmabuf_unmap_pages(umem_dmabuf);
dma_resv_unlock(dmabuf->resv);

dma_buf_detach(dmabuf, umem_dmabuf->attach);
dma_buf_put(dmabuf);
kfree(umem_dmabuf);
Expand Down
5 changes: 1 addition & 4 deletions drivers/infiniband/hw/mlx5/mlx5_ib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1285,8 +1285,7 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
struct ib_udata *udata,
int access_flags);
void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *mr);
void mlx5_ib_fence_odp_mr(struct mlx5_ib_mr *mr);
void mlx5_ib_fence_dmabuf_mr(struct mlx5_ib_mr *mr);
void mlx5_ib_free_odp_mr(struct mlx5_ib_mr *mr);
struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
u64 length, u64 virt_addr, int access_flags,
struct ib_pd *pd, struct ib_udata *udata);
Expand Down Expand Up @@ -1334,8 +1333,6 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);

struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
unsigned int entry, int access_flags);
void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
int mlx5_mr_cache_invalidate(struct mlx5_ib_mr *mr);

int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
struct ib_mr_status *mr_status);
Expand Down
133 changes: 62 additions & 71 deletions drivers/infiniband/hw/mlx5/mr.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ mlx5_ib_create_mkey_cb(struct mlx5_ib_dev *dev,
create_mkey_callback, context);
}

static void clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
static int mr_cache_max_order(struct mlx5_ib_dev *dev);
static void queue_adjust_cache_locked(struct mlx5_cache_ent *ent);

Expand Down Expand Up @@ -627,30 +625,10 @@ static struct mlx5_ib_mr *get_cache_mr(struct mlx5_cache_ent *req_ent)
return NULL;
}

static void detach_mr_from_cache(struct mlx5_ib_mr *mr)
static void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
{
struct mlx5_cache_ent *ent = mr->cache_ent;

mr->cache_ent = NULL;
spin_lock_irq(&ent->lock);
ent->total_mrs--;
spin_unlock_irq(&ent->lock);
}

void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
{
struct mlx5_cache_ent *ent = mr->cache_ent;

if (!ent)
return;

if (mlx5_mr_cache_invalidate(mr)) {
detach_mr_from_cache(mr);
destroy_mkey(dev, mr);
kfree(mr);
return;
}

spin_lock_irq(&ent->lock);
list_add_tail(&mr->list, &ent->head);
ent->available_mrs++;
Expand Down Expand Up @@ -1503,7 +1481,7 @@ static struct ib_mr *create_real_mr(struct ib_pd *pd, struct ib_umem *umem,
*/
err = mlx5_ib_update_mr_pas(mr, MLX5_IB_UPD_XLT_ENABLE);
if (err) {
dereg_mr(dev, mr);
mlx5_ib_dereg_mr(&mr->ibmr, NULL);
return ERR_PTR(err);
}
}
Expand Down Expand Up @@ -1560,7 +1538,7 @@ static struct ib_mr *create_user_odp_mr(struct ib_pd *pd, u64 start, u64 length,
return &mr->ibmr;

err_dereg_mr:
dereg_mr(dev, mr);
mlx5_ib_dereg_mr(&mr->ibmr, NULL);
return ERR_PTR(err);
}

Expand Down Expand Up @@ -1657,7 +1635,7 @@ struct ib_mr *mlx5_ib_reg_user_mr_dmabuf(struct ib_pd *pd, u64 offset,
return &mr->ibmr;

err_dereg_mr:
dereg_mr(dev, mr);
mlx5_ib_dereg_mr(&mr->ibmr, NULL);
return ERR_PTR(err);
}

Expand All @@ -1669,7 +1647,7 @@ struct ib_mr *mlx5_ib_reg_user_mr_dmabuf(struct ib_pd *pd, u64 offset,
* and any DMA inprogress will be completed. Failure of this function
* indicates the HW has failed catastrophically.
*/
int mlx5_mr_cache_invalidate(struct mlx5_ib_mr *mr)
static int mlx5_mr_cache_invalidate(struct mlx5_ib_mr *mr)
{
struct mlx5_umr_wr umrwr = {};

Expand Down Expand Up @@ -1941,69 +1919,82 @@ mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
}
}

static void clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
{
if (mr->ibmr.type == IB_MR_TYPE_INTEGRITY) {
struct mlx5_ib_mr *mr = to_mmr(ibmr);
struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
int rc;

/*
* Any async use of the mr must hold the refcount, once the refcount
* goes to zero no other thread, such as ODP page faults, prefetch, any
* UMR activity, etc can touch the mkey. Thus it is safe to destroy it.
*/
if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) &&
refcount_read(&mr->mmkey.usecount) != 0 &&
xa_erase(&mr_to_mdev(mr)->odp_mkeys, mlx5_base_mkey(mr->mmkey.key)))
mlx5r_deref_wait_odp_mkey(&mr->mmkey);

if (ibmr->type == IB_MR_TYPE_INTEGRITY) {
xa_cmpxchg(&dev->sig_mrs, mlx5_base_mkey(mr->mmkey.key), ibmr,
NULL, GFP_KERNEL);

if (mr->mtt_mr) {
rc = mlx5_ib_dereg_mr(&mr->mtt_mr->ibmr, NULL);
if (rc)
return rc;
mr->mtt_mr = NULL;
}
if (mr->klm_mr) {
mlx5_ib_dereg_mr(&mr->klm_mr->ibmr, NULL);
if (rc)
return rc;
mr->klm_mr = NULL;
}

if (mlx5_core_destroy_psv(dev->mdev,
mr->sig->psv_memory.psv_idx))
mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
mr->sig->psv_memory.psv_idx);
if (mlx5_core_destroy_psv(dev->mdev,
mr->sig->psv_wire.psv_idx))
if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx))
mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
mr->sig->psv_wire.psv_idx);
xa_erase(&dev->sig_mrs, mlx5_base_mkey(mr->mmkey.key));
kfree(mr->sig);
mr->sig = NULL;
}

/* Stop DMA */
if (mr->cache_ent) {
if (mlx5_mr_cache_invalidate(mr)) {
spin_lock_irq(&mr->cache_ent->lock);
mr->cache_ent->total_mrs--;
spin_unlock_irq(&mr->cache_ent->lock);
mr->cache_ent = NULL;
}
}
if (!mr->cache_ent) {
destroy_mkey(dev, mr);
mlx5_free_priv_descs(mr);
rc = destroy_mkey(to_mdev(mr->ibmr.device), mr);
if (rc)
return rc;
}
}

static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
{
struct ib_umem *umem = mr->umem;

/* Stop all DMA */
if (is_odp_mr(mr))
mlx5_ib_fence_odp_mr(mr);
else if (is_dmabuf_mr(mr))
mlx5_ib_fence_dmabuf_mr(mr);
else
clean_mr(dev, mr);
if (mr->umem) {
bool is_odp = is_odp_mr(mr);

if (umem) {
if (!is_odp_mr(mr))
atomic_sub(ib_umem_num_pages(umem),
if (!is_odp)
atomic_sub(ib_umem_num_pages(mr->umem),
&dev->mdev->priv.reg_pages);
ib_umem_release(umem);
ib_umem_release(mr->umem);
if (is_odp)
mlx5_ib_free_odp_mr(mr);
}

if (mr->cache_ent)
if (mr->cache_ent) {
mlx5_mr_cache_free(dev, mr);
else
} else {
mlx5_free_priv_descs(mr);
kfree(mr);
}

int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
{
struct mlx5_ib_mr *mmr = to_mmr(ibmr);

if (ibmr->type == IB_MR_TYPE_INTEGRITY) {
dereg_mr(to_mdev(mmr->mtt_mr->ibmr.device), mmr->mtt_mr);
dereg_mr(to_mdev(mmr->klm_mr->ibmr.device), mmr->klm_mr);
}

if (is_odp_mr(mmr) && to_ib_umem_odp(mmr->umem)->is_implicit_odp) {
mlx5_ib_free_implicit_mr(mmr);
return 0;
}

dereg_mr(to_mdev(ibmr->device), mmr);

return 0;
}

Expand Down Expand Up @@ -2175,10 +2166,10 @@ static int mlx5_alloc_integrity_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
destroy_mkey(dev, mr);
mlx5_free_priv_descs(mr);
err_free_mtt_mr:
dereg_mr(to_mdev(mr->mtt_mr->ibmr.device), mr->mtt_mr);
mlx5_ib_dereg_mr(&mr->mtt_mr->ibmr, NULL);
mr->mtt_mr = NULL;
err_free_klm_mr:
dereg_mr(to_mdev(mr->klm_mr->ibmr.device), mr->klm_mr);
mlx5_ib_dereg_mr(&mr->klm_mr->ibmr, NULL);
mr->klm_mr = NULL;
err_destroy_psv:
if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_memory.psv_idx))
Expand Down
Loading

0 comments on commit e6fb246

Please sign in to comment.