ib_srpt: Fix QP use-after-free triggered by SRP logout.

Fixed this by destroying cm_id before QP instead of after. The following
messages were logged if the use-after-free occurred:

mlx4_core 0000:08:00.0: command 0x19 failed: fw status = 0x9
ib_srpt: ***ERROR***: srpt_init_ch_qp() failed (-9)
ib_srpt: ***ERROR***: rejected SRP_LOGIN_REQ because creating a new RDMA channel failed.
ib_srpt: Rejecting login with reason 0x10001


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4139 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2012-02-18 10:24:25 +00:00
parent 1a6c43b1bc
commit 6e55334a9f
2 changed files with 12 additions and 14 deletions

View File

@@ -152,6 +152,7 @@ static void srpt_unregister_procfs_entry(struct scst_tgt_template *tgt);
static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
struct srpt_send_ioctx *ioctx);
static void srpt_drain_channel(struct ib_cm_id *cm_id);
static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch);
static void srpt_free_ch(struct scst_session *sess);
static enum rdma_ch_state srpt_set_ch_state_to_disc(struct srpt_rdma_ch *ch)
@@ -361,6 +362,8 @@ static const char *get_ch_state_name(enum rdma_ch_state s)
*/
static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch)
{
unsigned long flags;
TRACE_DBG("QP event %d on cm_id=%p sess_name=%s state=%s",
event->event, ch->cm_id, ch->sess_name,
get_ch_state_name(ch->state));
@@ -378,9 +381,11 @@ static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch)
case IB_EVENT_QP_LAST_WQE_REACHED:
TRACE_DBG("%s, state %s: received Last WQE event.",
ch->sess_name, get_ch_state_name(ch->state));
ch->last_wqe_received = true;
BUG_ON(!ch->thread);
spin_lock_irqsave(&ch->spinlock, flags);
ch->last_wqe_received = true;
wake_up_process(ch->thread);
spin_unlock_irqrestore(&ch->spinlock, flags);
break;
default:
PRINT_ERROR("received unrecognized IB QP event %d",
@@ -2033,10 +2038,13 @@ static int srpt_compl_thread(void *arg)
schedule();
}
complete(&ch->finished_processing_completions);
ib_destroy_cm_id(ch->cm_id);
while (!kthread_should_stop())
schedule();
srpt_destroy_ch_ib(ch);
/* Avoid that wake_up_process() races with thread exit. */
spin_lock_irq(&ch->spinlock);
spin_unlock_irq(&ch->spinlock);
return 0;
}
@@ -2243,12 +2251,6 @@ static void srpt_free_ch(struct scst_session *sess)
BUG_ON(!ch->thread);
BUG_ON(ch->thread == current);
while (wait_for_completion_timeout(&ch->finished_processing_completions,
10 * HZ) == 0)
PRINT_INFO("Waiting for completion processing thread ...");
srpt_destroy_ch_ib(ch);
srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
sdev, ch->rq_size,
ch->max_rsp_size, DMA_TO_DEVICE);
@@ -2257,8 +2259,6 @@ static void srpt_free_ch(struct scst_session *sess)
list_del(&ch->list);
spin_unlock_irq(&sdev->spinlock);
ib_destroy_cm_id(ch->cm_id);
kthread_stop(ch->thread);
ch->thread = NULL;
@@ -2430,7 +2430,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
ch->state = CH_CONNECTING;
INIT_LIST_HEAD(&ch->cmd_wait_list);
init_waitqueue_head(&ch->state_wq);
init_completion(&ch->finished_processing_completions);
ch->max_rsp_size = max_t(uint32_t, srp_max_rsp_size, MIN_MAX_RSP_SIZE);
ch->ioctx_ring = (struct srpt_send_ioctx **)
srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size,

View File

@@ -337,7 +337,6 @@ struct srpt_rdma_ch {
wait_queue_head_t state_wq;
struct list_head list;
struct list_head cmd_wait_list;
struct completion finished_processing_completions;
bool last_wqe_received;
struct scst_session *scst_sess;