summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@nvidia.com>2026-06-04 15:03:13 -0300
committerJason Gunthorpe <jgg@nvidia.com>2026-06-08 13:39:20 -0300
commitbadad6fad60def1b9805559dd81dbab3d97b82aa (patch)
treea2741f7f3cce228316e7801ef5e996a78da8862a /drivers
parent323c98a4ff06aa28114f2bf658fb43eb3b536bbc (diff)
downloadlwn-badad6fad60def1b9805559dd81dbab3d97b82aa.tar.gz
lwn-badad6fad60def1b9805559dd81dbab3d97b82aa.zip
RDMA: During rereg_mr ensure that REREG_ACCESS is compatible
If IB_MR_REREG_ACCESS changes from RO to RW then the umem has to be re-evaluated to ensure it is properly pinned as RW. Since the umem is hidden inside each driver's mr struct add a ib_umem_check_rereg() function that each driver has to call before processing IB_MR_REREG_ACCESS. mlx4 has to retain its duplicate ib_access_writable check because it implements IB_MR_REREG_ACCESS | IB_MR_REREG_TRANS by changing both items in place sequentially while the MR is live, so it will continue to not support this combination. Cc: stable@vger.kernel.org Fixes: b40656aa7d55 ("RDMA/umem: remove FOLL_FORCE usage") Link: https://patch.msgid.link/r/0-v1-06fb1a2d6cf5+107-rereg_access_jgg@nvidia.com Reported-by: Philip Tsukerman <philiptsukerman@gmail.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/core/umem.c16
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_mr.c4
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c4
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c4
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c4
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c5
6 files changed, 37 insertions, 0 deletions
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 786fa1aa8e55..4b055712b0d0 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -332,3 +332,19 @@ int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offset,
return 0;
}
EXPORT_SYMBOL(ib_umem_copy_from);
+
+/*
+ * Called during rereg mr if the driver is able to re-use a umem for
+ * IB_MR_REREG_ACCESS.
+ */
+int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags)
+{
+ if (!umem)
+ return 0;
+
+ if ((flags & IB_MR_REREG_ACCESS) && !(flags & IB_MR_REREG_TRANS))
+ if (ib_access_writable(new_access_flags) && !umem->writable)
+ return -EACCES;
+ return 0;
+}
+EXPORT_SYMBOL(ib_umem_check_rereg);
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index 896af1828a38..25bfd3970f5b 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -300,6 +300,10 @@ struct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start,
goto err_out;
}
+ ret = ib_umem_check_rereg(mr->pbl_mtr.umem, flags, mr_access_flags);
+ if (ret)
+ goto err_out;
+
mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
ret = PTR_ERR_OR_ZERO(mailbox);
if (ret)
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index 17086048d2d7..8cd427532805 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -3803,6 +3803,10 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags,
if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
return ERR_PTR(-EOPNOTSUPP);
+ ret = ib_umem_check_rereg(iwmr->region, flags, new_access);
+ if (ret)
+ return ERR_PTR(ret);
+
if (dmabuf_revocable) {
umem_dmabuf = to_ib_umem_dmabuf(iwmr->region);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 650b4a9121ff..6747bca30677 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -209,6 +209,10 @@ struct ib_mr *mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, u64 start,
struct mlx4_mpt_entry **pmpt_entry = &mpt_entry;
int err;
+ err = ib_umem_check_rereg(mmr->umem, flags, mr_access_flags);
+ if (err)
+ return ERR_PTR(err);
+
/* Since we synchronize this call and mlx4_ib_dereg_mr via uverbs,
* we assume that the calls can't run concurrently. Otherwise, a
* race exists.
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 3b6da45061a5..fb40b44496f4 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1179,6 +1179,10 @@ struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
return ERR_PTR(-EOPNOTSUPP);
+ err = ib_umem_check_rereg(mr->umem, flags, new_access_flags);
+ if (err)
+ return ERR_PTR(err);
+
if (!(flags & IB_MR_REREG_ACCESS))
new_access_flags = mr->access_flags;
if (!(flags & IB_MR_REREG_PD))
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 4d4891dc2884..4cf04a44189c 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -1319,6 +1319,7 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
struct rxe_mr *mr = to_rmr(ibmr);
struct rxe_pd *old_pd = to_rpd(ibmr->pd);
struct rxe_pd *pd = to_rpd(ibpd);
+ int err;
/* for now only support the two easy cases:
* rereg_pd and rereg_access
@@ -1328,6 +1329,10 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
return ERR_PTR(-EOPNOTSUPP);
}
+ err = ib_umem_check_rereg(mr->umem, flags, access);
+ if (err)
+ return ERR_PTR(err);
+
if (flags & IB_MR_REREG_PD) {
rxe_put(old_pd);
rxe_get(pd);