RDMA/iwcm: move iw_rem_ref() calls out of spinlock
kref release routines usually perform memory release operations,
hence, they should not be called with spinlocks held.
one such case is: SIW kref release routine siw_free_qp(), which
can sleep via vfree() while freeing queue memory.
Hence, all iw_rem_ref() calls in IWCM are moved out of spinlocks.
Fixes: 922a8e9fb2
("RDMA: iWARP Connection Manager.")
Signed-off-by: Krishnamraju Eraparaju <krishna2@chelsio.com>
Reviewed-by: Bernard Metzler <bmt@zurich.ibm.com>
Link: https://lore.kernel.org/r/20191007102627.12568-1-krishna2@chelsio.com
Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
612e0486ad
commit
54102dd410
|
@ -372,6 +372,7 @@ EXPORT_SYMBOL(iw_cm_disconnect);
|
||||||
static void destroy_cm_id(struct iw_cm_id *cm_id)
|
static void destroy_cm_id(struct iw_cm_id *cm_id)
|
||||||
{
|
{
|
||||||
struct iwcm_id_private *cm_id_priv;
|
struct iwcm_id_private *cm_id_priv;
|
||||||
|
struct ib_qp *qp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
|
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
|
||||||
|
@ -389,6 +390,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
|
||||||
set_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags);
|
set_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags);
|
||||||
|
|
||||||
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
||||||
|
qp = cm_id_priv->qp;
|
||||||
|
cm_id_priv->qp = NULL;
|
||||||
|
|
||||||
switch (cm_id_priv->state) {
|
switch (cm_id_priv->state) {
|
||||||
case IW_CM_STATE_LISTEN:
|
case IW_CM_STATE_LISTEN:
|
||||||
cm_id_priv->state = IW_CM_STATE_DESTROYING;
|
cm_id_priv->state = IW_CM_STATE_DESTROYING;
|
||||||
|
@ -401,7 +405,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
|
||||||
cm_id_priv->state = IW_CM_STATE_DESTROYING;
|
cm_id_priv->state = IW_CM_STATE_DESTROYING;
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
||||||
/* Abrupt close of the connection */
|
/* Abrupt close of the connection */
|
||||||
(void)iwcm_modify_qp_err(cm_id_priv->qp);
|
(void)iwcm_modify_qp_err(qp);
|
||||||
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
||||||
break;
|
break;
|
||||||
case IW_CM_STATE_IDLE:
|
case IW_CM_STATE_IDLE:
|
||||||
|
@ -426,11 +430,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
|
||||||
BUG();
|
BUG();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cm_id_priv->qp) {
|
|
||||||
cm_id_priv->id.device->ops.iw_rem_ref(cm_id_priv->qp);
|
|
||||||
cm_id_priv->qp = NULL;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
||||||
|
if (qp)
|
||||||
|
cm_id_priv->id.device->ops.iw_rem_ref(qp);
|
||||||
|
|
||||||
if (cm_id->mapped) {
|
if (cm_id->mapped) {
|
||||||
iwpm_remove_mapinfo(&cm_id->local_addr, &cm_id->m_local_addr);
|
iwpm_remove_mapinfo(&cm_id->local_addr, &cm_id->m_local_addr);
|
||||||
|
@ -671,11 +673,11 @@ int iw_cm_accept(struct iw_cm_id *cm_id,
|
||||||
BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
|
BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
|
||||||
cm_id_priv->state = IW_CM_STATE_IDLE;
|
cm_id_priv->state = IW_CM_STATE_IDLE;
|
||||||
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
||||||
if (cm_id_priv->qp) {
|
qp = cm_id_priv->qp;
|
||||||
cm_id->device->ops.iw_rem_ref(qp);
|
cm_id_priv->qp = NULL;
|
||||||
cm_id_priv->qp = NULL;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
||||||
|
if (qp)
|
||||||
|
cm_id->device->ops.iw_rem_ref(qp);
|
||||||
clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
|
clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
|
||||||
wake_up_all(&cm_id_priv->connect_wait);
|
wake_up_all(&cm_id_priv->connect_wait);
|
||||||
}
|
}
|
||||||
|
@ -696,7 +698,7 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
|
||||||
struct iwcm_id_private *cm_id_priv;
|
struct iwcm_id_private *cm_id_priv;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct ib_qp *qp;
|
struct ib_qp *qp = NULL;
|
||||||
|
|
||||||
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
|
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
|
||||||
|
|
||||||
|
@ -730,13 +732,13 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
|
||||||
return 0; /* success */
|
return 0; /* success */
|
||||||
|
|
||||||
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
||||||
if (cm_id_priv->qp) {
|
qp = cm_id_priv->qp;
|
||||||
cm_id->device->ops.iw_rem_ref(qp);
|
cm_id_priv->qp = NULL;
|
||||||
cm_id_priv->qp = NULL;
|
|
||||||
}
|
|
||||||
cm_id_priv->state = IW_CM_STATE_IDLE;
|
cm_id_priv->state = IW_CM_STATE_IDLE;
|
||||||
err:
|
err:
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
||||||
|
if (qp)
|
||||||
|
cm_id->device->ops.iw_rem_ref(qp);
|
||||||
clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
|
clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
|
||||||
wake_up_all(&cm_id_priv->connect_wait);
|
wake_up_all(&cm_id_priv->connect_wait);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -878,6 +880,7 @@ static int cm_conn_est_handler(struct iwcm_id_private *cm_id_priv,
|
||||||
static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
|
static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
|
||||||
struct iw_cm_event *iw_event)
|
struct iw_cm_event *iw_event)
|
||||||
{
|
{
|
||||||
|
struct ib_qp *qp = NULL;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -896,11 +899,13 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
|
||||||
cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
|
cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
|
||||||
} else {
|
} else {
|
||||||
/* REJECTED or RESET */
|
/* REJECTED or RESET */
|
||||||
cm_id_priv->id.device->ops.iw_rem_ref(cm_id_priv->qp);
|
qp = cm_id_priv->qp;
|
||||||
cm_id_priv->qp = NULL;
|
cm_id_priv->qp = NULL;
|
||||||
cm_id_priv->state = IW_CM_STATE_IDLE;
|
cm_id_priv->state = IW_CM_STATE_IDLE;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
||||||
|
if (qp)
|
||||||
|
cm_id_priv->id.device->ops.iw_rem_ref(qp);
|
||||||
ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
|
ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
|
||||||
|
|
||||||
if (iw_event->private_data_len)
|
if (iw_event->private_data_len)
|
||||||
|
@ -942,21 +947,18 @@ static void cm_disconnect_handler(struct iwcm_id_private *cm_id_priv,
|
||||||
static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
|
static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
|
||||||
struct iw_cm_event *iw_event)
|
struct iw_cm_event *iw_event)
|
||||||
{
|
{
|
||||||
|
struct ib_qp *qp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0, notify_event = 0;
|
||||||
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
||||||
|
qp = cm_id_priv->qp;
|
||||||
|
cm_id_priv->qp = NULL;
|
||||||
|
|
||||||
if (cm_id_priv->qp) {
|
|
||||||
cm_id_priv->id.device->ops.iw_rem_ref(cm_id_priv->qp);
|
|
||||||
cm_id_priv->qp = NULL;
|
|
||||||
}
|
|
||||||
switch (cm_id_priv->state) {
|
switch (cm_id_priv->state) {
|
||||||
case IW_CM_STATE_ESTABLISHED:
|
case IW_CM_STATE_ESTABLISHED:
|
||||||
case IW_CM_STATE_CLOSING:
|
case IW_CM_STATE_CLOSING:
|
||||||
cm_id_priv->state = IW_CM_STATE_IDLE;
|
cm_id_priv->state = IW_CM_STATE_IDLE;
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
notify_event = 1;
|
||||||
ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
|
|
||||||
spin_lock_irqsave(&cm_id_priv->lock, flags);
|
|
||||||
break;
|
break;
|
||||||
case IW_CM_STATE_DESTROYING:
|
case IW_CM_STATE_DESTROYING:
|
||||||
break;
|
break;
|
||||||
|
@ -965,6 +967,10 @@ static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
|
||||||
|
|
||||||
|
if (qp)
|
||||||
|
cm_id_priv->id.device->ops.iw_rem_ref(qp);
|
||||||
|
if (notify_event)
|
||||||
|
ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue