From: Leon Romanovsky <[email protected]>

In the current implementation, CQ umem is handled both by ib_core and
the driver. ib_core sometimes creates and destroys it, while the driver
also destroys it.

Store the umem in struct ib_cq and ensure that only ib_core manages
its lifetime, relying solely on its internal reference counter.

Signed-off-by: Leon Romanovsky <[email protected]>
---
 drivers/infiniband/core/umem.c                |  2 +-
 drivers/infiniband/core/uverbs_cmd.c          |  1 +
 drivers/infiniband/core/uverbs_std_types_cq.c |  7 ++++++-
 drivers/infiniband/core/verbs.c               |  2 ++
 drivers/infiniband/hw/efa/efa_verbs.c         | 24 +++++++++++-------------
 include/rdma/ib_verbs.h                       |  1 +
 6 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 8137031c2a65..fc70b918f3f0 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -283,7 +283,7 @@ EXPORT_SYMBOL(ib_umem_get);
  */
 void ib_umem_release(struct ib_umem *umem)
 {
-       if (!umem)
+       if (IS_ERR_OR_NULL(umem))
                return;
        if (umem->is_dmabuf)
                return ib_umem_dmabuf_release(to_ib_umem_dmabuf(umem));
diff --git a/drivers/infiniband/core/uverbs_cmd.c 
b/drivers/infiniband/core/uverbs_cmd.c
index f4616deeca54..fb19395b9f2a 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1085,6 +1085,7 @@ static int create_cq(struct uverbs_attr_bundle *attrs,
        return uverbs_response(attrs, &resp, sizeof(resp));
 
 err_free:
+       ib_umem_release(cq->umem);
        rdma_restrack_put(&cq->res);
        kfree(cq);
 err_file:
diff --git a/drivers/infiniband/core/uverbs_std_types_cq.c 
b/drivers/infiniband/core/uverbs_std_types_cq.c
index fab5d914029d..05809f9ff0f6 100644
--- a/drivers/infiniband/core/uverbs_std_types_cq.c
+++ b/drivers/infiniband/core/uverbs_std_types_cq.c
@@ -186,6 +186,11 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
        cq->comp_handler  = ib_uverbs_comp_handler;
        cq->event_handler = ib_uverbs_cq_event_handler;
        cq->cq_context    = ev_file ? &ev_file->ev_queue : NULL;
+       /*
+        * If UMEM is not provided here, legacy drivers will set it during
+        * CQ creation based on their internal udata.
+        */
+       cq->umem = umem;
        atomic_set(&cq->usecnt, 0);
 
        rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ);
@@ -206,7 +211,7 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
        return ret;
 
 err_free:
-       ib_umem_release(umem);
+       ib_umem_release(cq->umem);
        rdma_restrack_put(&cq->res);
        kfree(cq);
 err_event_file:
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 47a97797d7be..ad48d2458a3f 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -49,6 +49,7 @@
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_cache.h>
 #include <rdma/ib_addr.h>
+#include <rdma/ib_umem.h>
 #include <rdma/rw.h>
 #include <rdma/lag.h>
 
@@ -2249,6 +2250,7 @@ int ib_destroy_cq_user(struct ib_cq *cq, struct ib_udata 
*udata)
        if (ret)
                return ret;
 
+       ib_umem_release(cq->umem);
        rdma_restrack_del(&cq->res);
        kfree(cq);
        return ret;
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c 
b/drivers/infiniband/hw/efa/efa_verbs.c
index 19e3033d4ff7..ae9b98b4b528 100644
--- a/drivers/infiniband/hw/efa/efa_verbs.c
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
@@ -1083,15 +1083,14 @@ int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata 
*udata)
                  cq->cq_idx, cq->cpu_addr, cq->size, &cq->dma_addr);
 
        efa_destroy_cq_idx(dev, cq->cq_idx);
-       efa_cq_user_mmap_entries_remove(cq);
+       if (cq->cpu_addr)
+               efa_cq_user_mmap_entries_remove(cq);
        if (cq->eq) {
                xa_erase(&dev->cqs_xa, cq->cq_idx);
                synchronize_irq(cq->eq->irq.irqn);
        }
 
-       if (cq->umem)
-               ib_umem_release(cq->umem);
-       else
+       if (cq->cpu_addr)
                efa_free_mapped(dev, cq->cpu_addr, cq->dma_addr, cq->size, 
DMA_FROM_DEVICE);
        return 0;
 }
@@ -1212,22 +1211,20 @@ int efa_create_cq_umem(struct ib_cq *ibcq, const struct 
ib_cq_init_attr *attr,
        cq->ucontext = ucontext;
        cq->size = PAGE_ALIGN(cmd.cq_entry_size * entries * cmd.num_sub_cqs);
 
-       if (umem) {
-               if (umem->length < cq->size) {
+       if (ibcq->umem) {
+               if (ibcq->umem->length < cq->size) {
                        ibdev_dbg(&dev->ibdev, "External memory too small\n");
                        err = -EINVAL;
                        goto err_out;
                }
 
-               if (!ib_umem_is_contiguous(umem)) {
+               if (!ib_umem_is_contiguous(ibcq->umem)) {
                        ibdev_dbg(&dev->ibdev, "Non contiguous CQ 
unsupported\n");
                        err = -EINVAL;
                        goto err_out;
                }
 
-               cq->cpu_addr = NULL;
-               cq->dma_addr = ib_umem_start_dma_addr(umem);
-               cq->umem = umem;
+               cq->dma_addr = ib_umem_start_dma_addr(ibcq->umem);
        } else {
                cq->cpu_addr = efa_zalloc_mapped(dev, &cq->dma_addr, cq->size,
                                                 DMA_FROM_DEVICE);
@@ -1259,7 +1256,7 @@ int efa_create_cq_umem(struct ib_cq *ibcq, const struct 
ib_cq_init_attr *attr,
        cq->ibcq.cqe = result.actual_depth;
        WARN_ON_ONCE(entries != result.actual_depth);
 
-       if (!umem)
+       if (cq->cpu_addr)
                err = cq_mmap_entries_setup(dev, cq, &resp, result.db_valid);
 
        if (err) {
@@ -1296,11 +1293,12 @@ int efa_create_cq_umem(struct ib_cq *ibcq, const struct 
ib_cq_init_attr *attr,
        if (cq->eq)
                xa_erase(&dev->cqs_xa, cq->cq_idx);
 err_remove_mmap:
-       efa_cq_user_mmap_entries_remove(cq);
+       if (cq->cpu_addr)
+               efa_cq_user_mmap_entries_remove(cq);
 err_destroy_cq:
        efa_destroy_cq_idx(dev, cq->cq_idx);
 err_free_mapped:
-       if (!umem)
+       if (cq->cpu_addr)
                efa_free_mapped(dev, cq->cpu_addr, cq->dma_addr, cq->size,
                                DMA_FROM_DEVICE);
 err_out:
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index e1ec5a6c74e6..b1e34fd2ed5f 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1649,6 +1649,7 @@ struct ib_cq {
        u8 interrupt:1;
        u8 shared:1;
        unsigned int comp_vector;
+       struct ib_umem *umem;
 
        /*
         * Implementation details of the RDMA core, don't use in drivers:

-- 
2.52.0


Reply via email to