summaryrefslogtreecommitdiff
path: root/drivers/infiniband/hw/mlx5/mr.c
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@nvidia.com>2020-11-30 10:58:37 +0300
committerJason Gunthorpe <jgg@nvidia.com>2020-12-07 21:06:23 +0300
commit6e0954b11c056570cb29676a84e2f8dc4d1dd05e (patch)
tree0c72abb6ece5e7f6fb2bde31a5d0596020e22840 /drivers/infiniband/hw/mlx5/mr.c
parentadac4cb3c1ff5c47c9f47be5d017a0e054176e3c (diff)
downloadlinux-6e0954b11c056570cb29676a84e2f8dc4d1dd05e.tar.xz
RDMA/uverbs: Allow drivers to create a new HW object during rereg_mr
mlx5 has an ugly flow where it tries to allocate a new MR and replace the existing MR in the same memory during rereg. This is very complicated and buggy. Instead of trying to replace in-place inside the driver, provide support from uverbs to change the entire HW object assigned to a handle during rereg_mr. Since destroying a MR is allowed to fail (ie if a MW is pointing at it) and can't be detected in advance, the algorithm creates a completely new uobject to hold the new MR and swaps the IDR entries of the two objects. The old MR in the temporary IDR entry is destroyed, and if it fails rereg_mr succeeds and destruction is deferred to FD release. This complexity is why this cannot live in a driver safely. Link: https://lore.kernel.org/r/20201130075839.278575-4-leon@kernel.org Signed-off-by: Leon Romanovsky <leonro@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Diffstat (limited to 'drivers/infiniband/hw/mlx5/mr.c')
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index b6116f6d065d..778cc08e17ad 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1620,9 +1620,10 @@ static int rereg_umr(struct ib_pd *pd, struct mlx5_ib_mr *mr,
return err;
}
-int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
- u64 length, u64 virt_addr, int new_access_flags,
- struct ib_pd *new_pd, struct ib_udata *udata)
+struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
+ u64 length, u64 virt_addr,
+ int new_access_flags, struct ib_pd *new_pd,
+ struct ib_udata *udata)
{
struct mlx5_ib_dev *dev = to_mdev(ib_mr->device);
struct mlx5_ib_mr *mr = to_mmr(ib_mr);
@@ -1638,10 +1639,10 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
start, virt_addr, length, access_flags);
if (!mr->umem)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
if (is_odp_mr(mr))
- return -EOPNOTSUPP;
+ return ERR_PTR(-EOPNOTSUPP);
if (flags & IB_MR_REREG_TRANS) {
addr = virt_addr;
@@ -1717,14 +1718,14 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
set_mr_fields(dev, mr, len, access_flags);
- return 0;
+ return NULL;
err:
ib_umem_release(mr->umem);
mr->umem = NULL;
clean_mr(dev, mr);
- return err;
+ return ERR_PTR(err);
}
static int