]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
RDMA: During rereg_mr ensure that REREG_ACCESS is compatible
authorJason Gunthorpe <jgg@nvidia.com>
Mon, 15 Jun 2026 21:29:10 +0000 (17:29 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Jun 2026 11:42:37 +0000 (13:42 +0200)
[ Upstream commit badad6fad60def1b9805559dd81dbab3d97b82aa ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/infiniband/core/umem.c
drivers/infiniband/hw/hns/hns_roce_mr.c
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/hw/mlx4/mr.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/sw/rxe/rxe_verbs.c
include/rdma/ib_umem.h

index c5b68639476058bb45e3e2bb0c153e8c9d84e5ac..fd3a774904f8d203cd819bbcea73f65310a67b75 100644 (file)
@@ -326,3 +326,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);
index 55b9283bfc6f030f874955aede1992225aed2f0e..f86859ffb413ecebe9f1bd6897b66489b4f41cf2 100644 (file)
@@ -292,6 +292,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)
index 0b9cf175ed73b48e3e000b0bf6456fb44e078913..04015eb3663d6f9d166c03b1d171c60f1a662d69 100644 (file)
@@ -3245,6 +3245,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);
+
        ret = irdma_hwdereg_mr(ib_mr);
        if (ret)
                return ERR_PTR(ret);
index a40bf58bcdd3ae0797199f2f5d51d311b0e4931a..04c370fbdba0958a8b273168f79177219ae49b8e 100644 (file)
@@ -466,6 +466,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.
index 726b81b6330c65fe07512060833e18122b1d4cc4..c8238db895bf16c8b14678fb3151599c82f120db 100644 (file)
@@ -1829,6 +1829,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))
index 589ac0d8489dbd8fc3a49090852bb16632d88d4c..9466fed6726b42bac28e540275877e1106403b1a 100644 (file)
@@ -1312,6 +1312,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
@@ -1321,6 +1322,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);
index 75f5acad646b4308735fd30e04fc5fc2f0f88a4f..7060ab90267c076902c12f03e35e6d7abb23c50f 100644 (file)
@@ -163,6 +163,8 @@ void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf);
 void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf);
 void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf);
 
+int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags);
+
 #else /* CONFIG_INFINIBAND_USER_MEM */
 
 #include <linux/err.h>
@@ -225,5 +227,11 @@ static inline void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf
 static inline void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf) {}
 static inline void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf) {}
 
+static inline int ib_umem_check_rereg(struct ib_umem *umem, int flags,
+                                     int new_access_flags)
+{
+       return -EOPNOTSUPP;
+}
+
 #endif /* CONFIG_INFINIBAND_USER_MEM */
 #endif /* IB_UMEM_H */