From ab69b20fe2a4c6b3f04d9b5ae3fd468f75967e53 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 5 Jun 2011 10:00:57 +0000 Subject: [PATCH] ib_srpt: Fix a recently introduced RHEL 5 / CentOS 5 deadlock triggered by initiator logout git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3545 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- srpt/src/ib_srpt.c | 92 +++++++++++++++++----------------------------- srpt/src/ib_srpt.h | 2 - 2 files changed, 33 insertions(+), 61 deletions(-) diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 364266371..e49d1a37b 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -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_release_channel(struct srpt_rdma_ch *ch); +static void srpt_free_ch(struct scst_session *sess); static enum rdma_ch_state srpt_set_ch_state(struct srpt_rdma_ch *ch, enum rdma_ch_state new_state) @@ -1883,15 +1884,23 @@ static int srpt_compl_thread(void *arg) /* Hibernation / freezing of the SRPT kernel thread is not supported. */ current->flags |= PF_NOFREEZE; + allow_signal(SIGTERM); ch = arg; BUG_ON(!ch); - while (!kthread_should_stop()) { + while (!kthread_should_stop() && !signal_pending(current)) { set_current_state(TASK_INTERRUPTIBLE); srpt_process_completion(ch->cq, ch, SCST_CONTEXT_THREAD, SCST_CONTEXT_DIRECT); schedule(); } + set_current_state(TASK_RUNNING); + + disallow_signal(SIGTERM); + flush_signals(current); + + scst_unregister_session(ch->scst_sess, false, srpt_free_ch); + return 0; } @@ -1955,17 +1964,6 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) if (ret) goto err_destroy_qp; - TRACE_DBG("creating IB completion thread for session %s", - ch->sess_name); - - ch->thread = kthread_run(srpt_compl_thread, ch, "ib_srpt_compl"); - if (IS_ERR(ch->thread)) { - PRINT_ERROR("failed to create kernel thread %ld", - PTR_ERR(ch->thread)); - ch->thread = NULL; - goto err_destroy_qp; - } - out: kfree(qp_init); return ret; @@ -1981,11 +1979,6 @@ static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch) { TRACE_ENTRY(); - if (ch->thread) { - kthread_stop(ch->thread); - ch->thread = NULL; - } - while (ib_poll_cq(ch->cq, ARRAY_SIZE(ch->wc), ch->wc) > 0) ; @@ -2065,13 +2058,11 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id) { struct srpt_rdma_ch *ch; int ret; - bool do_reset; WARN_ON_ONCE(irqs_disabled()); ch = cm_id->context; - do_reset = srpt_set_ch_state_to_draining(ch); - if (do_reset) { + if (srpt_set_ch_state_to_draining(ch)) { ret = srpt_ch_qp_err(ch); if (ret < 0) PRINT_ERROR("Setting queue pair in error state" @@ -2081,61 +2072,37 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id) /** * srpt_release_channel() - Release channel resources. - * - * Schedules the actual release not only because invoking ib_destroy_cm_id() - * directly from inside an IB CM callback function would trigger a deadlock - * but also because scst_unregister_session() can sleep. */ static void srpt_release_channel(struct srpt_rdma_ch *ch) { - TRACE_ENTRY(); - - WARN_ON(ch->state != CH_RELEASING); - schedule_work(&ch->release_work); - - TRACE_EXIT(); + kill_pid(task_pid(ch->thread), SIGTERM, 1); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19) -/* A vanilla 2.6.19 or older kernel without backported OFED kernel headers. */ -static void srpt_release_channel_work(void *ctx) -#else -static void srpt_release_channel_work(struct work_struct *w) -#endif +static void srpt_free_ch(struct scst_session *sess) { struct srpt_rdma_ch *ch; struct srpt_device *sdev; TRACE_ENTRY(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19) - ch = ctx; -#else - ch = container_of(w, struct srpt_rdma_ch, release_work); -#endif - BUG_ON(!ch); - TRACE_DBG("ch = %p; ch->scst_sess = %p", ch, ch->scst_sess); - WARN_ON(ch->state != CH_RELEASING); - + ch = scst_sess_get_tgt_priv(sess); + BUG_ON(ch->scst_sess != sess); sdev = ch->sport->sdev; BUG_ON(!sdev); - if (ch->thread) { - kthread_stop(ch->thread); - ch->thread = NULL; - } + BUG_ON(!ch->thread); + kthread_stop(ch->thread); + ch->thread = NULL; /* * Unregister the session and wait until processing of all commands * associated with the session has finished. */ - scst_unregister_session(ch->scst_sess, true, NULL); - ch->scst_sess = NULL; srpt_destroy_ch_ib(ch); srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring, - ch->sport->sdev, ch->rq_size, + sdev, ch->rq_size, srp_max_rsp_size, DMA_TO_DEVICE); spin_lock_irq(&sdev->spinlock); @@ -2325,11 +2292,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto reject; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19) - INIT_WORK(&ch->release_work, srpt_release_channel_work, ch); -#else - INIT_WORK(&ch->release_work, srpt_release_channel_work); -#endif memcpy(ch->i_port_id, req->initiator_port_id, 16); memcpy(ch->t_port_id, req->target_port_id, 16); ch->sport = &sdev->port[param->port - 1]; @@ -2365,13 +2327,21 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto free_ring; } + ch->thread = kthread_run(srpt_compl_thread, ch, "ib_srpt_compl"); + if (IS_ERR(ch->thread)) { + PRINT_ERROR("failed to create kernel thread %ld", + PTR_ERR(ch->thread)); + ch->thread = NULL; + goto destroy_ib; + } + ret = srpt_ch_qp_rtr(ch, ch->qp); if (ret) { rej->reason = __constant_cpu_to_be32( SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); PRINT_ERROR("rejected SRP_LOGIN_REQ because enabling" " RTR failed (error code = %d)", ret); - goto destroy_ib; + goto stop_kthread; } if (use_port_guid_in_session_name) { @@ -2451,9 +2421,13 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, release_channel: srpt_set_ch_state(ch, CH_DISCONNECTING); - scst_unregister_session(ch->scst_sess, 0, NULL); + scst_unregister_session(ch->scst_sess, false, NULL); ch->scst_sess = NULL; +stop_kthread: + kthread_stop(ch->thread); + ch->thread = NULL; + destroy_ib: srpt_destroy_ch_ib(ch); diff --git a/srpt/src/ib_srpt.h b/srpt/src/ib_srpt.h index 290a20264..b0cf98665 100644 --- a/srpt/src/ib_srpt.h +++ b/srpt/src/ib_srpt.h @@ -291,7 +291,6 @@ enum rdma_ch_state { * against concurrent modification by the cm_id spinlock. * @scst_sess: SCST session information associated with this SRP channel. * @sess_name: SCST session name. - * @release_work: */ struct srpt_rdma_ch { struct task_struct *thread; @@ -316,7 +315,6 @@ struct srpt_rdma_ch { struct scst_session *scst_sess; u8 sess_name[36]; - struct work_struct release_work; }; /**