]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RDMA/core: Add driver APIs pre_destroy_cq() and post_destroy_cq()
authorMark Zhang <markzhang@nvidia.com>
Mon, 16 Jun 2025 08:26:20 +0000 (11:26 +0300)
committerLeon Romanovsky <leon@kernel.org>
Wed, 25 Jun 2025 07:49:51 +0000 (03:49 -0400)
Currently in ib_free_cq, it disables IRQ or cancel the CQ work before
driver destroy_cq. This isn't good as a new IRQ or a CQ work can be
submitted immediately after disabling IRQ or canceling CQ work, which
may run concurrently with destroy_cq and cause crashes.
The right flow should be:
 1. Driver disables CQ to make sure no new CQ event will be submitted;
 2. Disables IRQ or Cancels CQ work in core layer, to make sure no CQ
    polling work is running;
 3. Free all resources to destroy the CQ.

This patch adds 2 driver APIs:
- pre_destroy_cq(): Disable a CQ to prevent it from generating any new
  work completions, but not free any kernel resources;
- post_destroy_cq(): Free all kernel resources.

In ib_free_cq, the IRQ is disabled or CQ work is canceled after
pre_destroy_cq, and before post_destroy_cq.

Fixes: 14d3a3b2498e ("IB: add a proper completion queue abstraction")
Signed-off-by: Mark Zhang <markzhang@nvidia.com>
Link: https://patch.msgid.link/b5f7ae3d75f44a3e15ff3f4eb2bbdea13e06b97f.1750062328.git.leon@kernel.org
Signed-off-by: Leon Romanovsky <leon@kernel.org>
drivers/infiniband/core/cq.c
drivers/infiniband/core/device.c
include/rdma/ib_verbs.h

index a70876a0a23126f7c48f2e752516cf6f133d722f..584537c71545cc6ac807b4af26594598afafb0aa 100644 (file)
@@ -317,13 +317,18 @@ EXPORT_SYMBOL(__ib_alloc_cq_any);
  */
 void ib_free_cq(struct ib_cq *cq)
 {
-       int ret;
+       int ret = 0;
 
        if (WARN_ON_ONCE(atomic_read(&cq->usecnt)))
                return;
        if (WARN_ON_ONCE(cq->cqe_used))
                return;
 
+       if (cq->device->ops.pre_destroy_cq) {
+               ret = cq->device->ops.pre_destroy_cq(cq);
+               WARN_ONCE(ret, "Disable of kernel CQ shouldn't fail");
+       }
+
        switch (cq->poll_ctx) {
        case IB_POLL_DIRECT:
                break;
@@ -340,7 +345,10 @@ void ib_free_cq(struct ib_cq *cq)
 
        rdma_dim_destroy(cq);
        trace_cq_free(cq);
-       ret = cq->device->ops.destroy_cq(cq, NULL);
+       if (cq->device->ops.post_destroy_cq)
+               cq->device->ops.post_destroy_cq(cq);
+       else
+               ret = cq->device->ops.destroy_cq(cq, NULL);
        WARN_ONCE(ret, "Destroy of kernel CQ shouldn't fail");
        rdma_restrack_del(&cq->res);
        kfree(cq->wc);
index d4263385850a7aac61c2cd6931d1d08bbbe35838..468ed6bd472207054eff714f8b8d9d8a3dd1408a 100644 (file)
@@ -2763,8 +2763,10 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
        SET_DEVICE_OP(dev_ops, modify_srq);
        SET_DEVICE_OP(dev_ops, modify_wq);
        SET_DEVICE_OP(dev_ops, peek_cq);
+       SET_DEVICE_OP(dev_ops, pre_destroy_cq);
        SET_DEVICE_OP(dev_ops, poll_cq);
        SET_DEVICE_OP(dev_ops, port_groups);
+       SET_DEVICE_OP(dev_ops, post_destroy_cq);
        SET_DEVICE_OP(dev_ops, post_recv);
        SET_DEVICE_OP(dev_ops, post_send);
        SET_DEVICE_OP(dev_ops, post_srq_recv);
index af43a8d2a74aec87b0bddc8e36c6650b20cd796c..38f68d245fa6e20a923bf6993570d9ab695c2c16 100644 (file)
@@ -2489,6 +2489,15 @@ struct ib_device_ops {
        int (*modify_cq)(struct ib_cq *cq, u16 cq_count, u16 cq_period);
        int (*destroy_cq)(struct ib_cq *cq, struct ib_udata *udata);
        int (*resize_cq)(struct ib_cq *cq, int cqe, struct ib_udata *udata);
+       /**
+        * pre_destroy_cq - Prevent a cq from generating any new work
+        * completions, but not free any kernel resources
+        */
+       int (*pre_destroy_cq)(struct ib_cq *cq);
+       /**
+        * post_destroy_cq - Free all kernel resources
+        */
+       void (*post_destroy_cq)(struct ib_cq *cq);
        struct ib_mr *(*get_dma_mr)(struct ib_pd *pd, int mr_access_flags);
        struct ib_mr *(*reg_user_mr)(struct ib_pd *pd, u64 start, u64 length,
                                     u64 virt_addr, int mr_access_flags,