Commit f4a87ca1 authored by Mustafa Ismail's avatar Mustafa Ismail Committed by Doug Ledford

i40iw: Fix double free of QP

A QP can be double freed if i40iw_cm_disconn() is
called while it is currently being freed by
i40iw_rem_ref(). The fix in i40iw_cm_disconn() will
first check if the QP is already freed before
making another request for the QP to be freed.
Signed-off-by: default avatarMustafa Ismail <mustafa.ismail@intel.com>
Signed-off-by: default avatarShiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: default avatarHenry Orosco <henry.orosco@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 91c42b72
...@@ -512,7 +512,7 @@ u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev); ...@@ -512,7 +512,7 @@ u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev);
int i40iw_register_rdma_device(struct i40iw_device *iwdev); int i40iw_register_rdma_device(struct i40iw_device *iwdev);
void i40iw_port_ibevent(struct i40iw_device *iwdev); void i40iw_port_ibevent(struct i40iw_device *iwdev);
int i40iw_cm_disconn(struct i40iw_qp *); void i40iw_cm_disconn(struct i40iw_qp *iwqp);
void i40iw_cm_disconn_worker(void *); void i40iw_cm_disconn_worker(void *);
int mini_cm_recv_pkt(struct i40iw_cm_core *, struct i40iw_device *, int mini_cm_recv_pkt(struct i40iw_cm_core *, struct i40iw_device *,
struct sk_buff *); struct sk_buff *);
......
...@@ -3359,21 +3359,33 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp, ...@@ -3359,21 +3359,33 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp,
* i40iw_cm_disconn - when a connection is being closed * i40iw_cm_disconn - when a connection is being closed
* @iwqp: associate qp for the connection * @iwqp: associate qp for the connection
*/ */
int i40iw_cm_disconn(struct i40iw_qp *iwqp) void i40iw_cm_disconn(struct i40iw_qp *iwqp)
{ {
struct disconn_work *work; struct disconn_work *work;
struct i40iw_device *iwdev = iwqp->iwdev; struct i40iw_device *iwdev = iwqp->iwdev;
struct i40iw_cm_core *cm_core = &iwdev->cm_core; struct i40iw_cm_core *cm_core = &iwdev->cm_core;
unsigned long flags;
work = kzalloc(sizeof(*work), GFP_ATOMIC); work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work) if (!work)
return -ENOMEM; /* Timer will clean up */ return; /* Timer will clean up */
spin_lock_irqsave(&iwdev->qptable_lock, flags);
if (!iwdev->qp_table[iwqp->ibqp.qp_num]) {
spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
"%s qp_id %d is already freed\n",
__func__, iwqp->ibqp.qp_num);
kfree(work);
return;
}
i40iw_add_ref(&iwqp->ibqp); i40iw_add_ref(&iwqp->ibqp);
spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
work->iwqp = iwqp; work->iwqp = iwqp;
INIT_WORK(&work->work, i40iw_disconnect_worker); INIT_WORK(&work->work, i40iw_disconnect_worker);
queue_work(cm_core->disconn_wq, &work->work); queue_work(cm_core->disconn_wq, &work->work);
return 0; return;
} }
/** /**
......
...@@ -308,7 +308,9 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) ...@@ -308,7 +308,9 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)
iwqp = iwdev->qp_table[info->qp_cq_id]; iwqp = iwdev->qp_table[info->qp_cq_id];
if (!iwqp) { if (!iwqp) {
spin_unlock_irqrestore(&iwdev->qptable_lock, flags); spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
i40iw_pr_err("qp_id %d is already freed\n", info->qp_cq_id); i40iw_debug(dev, I40IW_DEBUG_AEQ,
"%s qp_id %d is already freed\n",
__func__, info->qp_cq_id);
continue; continue;
} }
i40iw_add_ref(&iwqp->ibqp); i40iw_add_ref(&iwqp->ibqp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment