RDMA/i40iw: Add qp table lock around AE processing
authorIsmail, Mustafa <mustafa.ismail@intel.com>
Mon, 18 Apr 2016 15:32:59 +0000 (10:32 -0500)
committerDoug Ledford <dledford@redhat.com>
Thu, 28 Apr 2016 20:32:53 +0000 (16:32 -0400)
QP may be freed during Async Event processing.
Add a lock around QP table to prevent it.

Signed-off-by: Mustafa Ismail <mustafa.ismail@intel.com>
Signed-off-by: Faisal Latif <faisal.latif@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/i40iw/i40iw.h
drivers/infiniband/hw/i40iw/i40iw_hw.c
drivers/infiniband/hw/i40iw/i40iw_utils.c

index 81976768144555a4c0f578c71ede72ff8644beaf..bf3627fea222c8f0cace594e50a5a6186ef64b5c 100644 (file)
@@ -254,6 +254,7 @@ struct i40iw_device {
        u32 arp_table_size;
        u32 next_arp_index;
        spinlock_t resource_lock; /* hw resource access */
+       spinlock_t qptable_lock;
        u32 vendor_id;
        u32 vendor_part_id;
        u32 of_device_registered;
index 9fd302425563948ab9884e7fd12faec4db576726..27cfdd854754bcc5be219042ad3daddccc7d1303 100644 (file)
@@ -106,6 +106,7 @@ u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev)
        set_bit(2, iwdev->allocated_pds);
 
        spin_lock_init(&iwdev->resource_lock);
+       spin_lock_init(&iwdev->qptable_lock);
        mrdrvbits = 24 - get_count_order(iwdev->max_mr);
        iwdev->mr_stagmask = ~(((1 << mrdrvbits) - 1) << (32 - mrdrvbits));
        return 0;
@@ -301,11 +302,15 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)
                            "%s ae_id = 0x%x bool qp=%d qp_id = %d\n",
                            __func__, info->ae_id, info->qp, info->qp_cq_id);
                if (info->qp) {
+                       spin_lock_irqsave(&iwdev->qptable_lock, flags);
                        iwqp = iwdev->qp_table[info->qp_cq_id];
                        if (!iwqp) {
+                               spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
                                i40iw_pr_err("qp_id %d is already freed\n", info->qp_cq_id);
                                continue;
                        }
+                       i40iw_add_ref(&iwqp->ibqp);
+                       spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
                        qp = &iwqp->sc_qp;
                        spin_lock_irqsave(&iwqp->lock, flags);
                        iwqp->hw_tcp_state = info->tcp_state;
@@ -411,6 +416,8 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)
                                i40iw_terminate_connection(qp, info);
                                break;
                }
+               if (info->qp)
+                       i40iw_rem_ref(&iwqp->ibqp);
        } while (1);
 
        if (aeqcnt)
index 1ceec81bd8eb3ff95428d36a1eeefc86295c576b..7ed998c573a4214aff56a71e80bfcb8bc61531d3 100644 (file)
@@ -506,14 +506,19 @@ void i40iw_rem_ref(struct ib_qp *ibqp)
        struct cqp_commands_info *cqp_info;
        struct i40iw_device *iwdev;
        u32 qp_num;
+       unsigned long flags;
 
        iwqp = to_iwqp(ibqp);
-       if (!atomic_dec_and_test(&iwqp->refcount))
+       iwdev = iwqp->iwdev;
+       spin_lock_irqsave(&iwdev->qptable_lock, flags);
+       if (!atomic_dec_and_test(&iwqp->refcount)) {
+               spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
                return;
+       }
 
-       iwdev = iwqp->iwdev;
        qp_num = iwqp->ibqp.qp_num;
        iwdev->qp_table[qp_num] = NULL;
+       spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
        cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false);
        if (!cqp_request)
                return;