From: <bva...@us...> - 2011-12-20 20:39:27
|
Revision: 4020 http://scst.svn.sourceforge.net/scst/?rev=4020&view=rev Author: bvassche Date: 2011-12-20 20:39:20 +0000 (Tue, 20 Dec 2011) Log Message: ----------- ib_srpt: Avoid that very rapidly successive logins from the same initiator cause a crash Modified Paths: -------------- trunk/srpt/src/ib_srpt.c Modified: trunk/srpt/src/ib_srpt.c =================================================================== --- trunk/srpt/src/ib_srpt.c 2011-12-20 15:37:54 UTC (rev 4019) +++ trunk/srpt/src/ib_srpt.c 2011-12-20 20:39:20 UTC (rev 4020) @@ -2313,7 +2313,8 @@ struct srp_login_rsp *rsp; struct srp_login_rej *rej; struct ib_cm_rep_param *rep_param; - struct srpt_rdma_ch *ch, *tmp_ch; + struct srpt_rdma_ch *ch; + struct task_struct *thread; u32 it_iu_len; int i; int ret = 0; @@ -2374,33 +2375,6 @@ goto reject; } - if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { - rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; - - spin_lock_irq(&sdev->spinlock); - - list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list) { - if (!memcmp(ch->i_port_id, req->initiator_port_id, 16) - && !memcmp(ch->t_port_id, req->target_port_id, 16) - && param->port == ch->sport->port - && param->listen_id == ch->sport->sdev->cm_id - && ch->cm_id) { - if (!__srpt_close_ch(ch)) - continue; - - TRACE_DBG("Found existing channel %s; cm_id =" - " %p", ch->sess_name, ch->cm_id); - - rsp->rsp_flags = - SRP_LOGIN_RSP_MULTICHAN_TERMINATED; - } - } - - spin_unlock_irq(&sdev->spinlock); - - } else - rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; - if (*(__be64 *)req->target_port_id != cpu_to_be64(srpt_service_guid) || *(__be64 *)(req->target_port_id + 8) != cpu_to_be64(srpt_service_guid)) { @@ -2493,20 +2467,43 @@ goto destroy_ib; } + thread = kthread_run(srpt_compl_thread, ch, "srpt_%s", + ch->sport->sdev->device->name); + if (IS_ERR(thread)) { + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + PRINT_ERROR("failed to create kernel thread %ld", PTR_ERR(ch->thread)); + goto unreg_ch; + } + spin_lock_irq(&sdev->spinlock); + if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { + struct srpt_rdma_ch *ch2; + + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; + list_for_each_entry(ch2, &sdev->rch_list, list) { + if (!memcmp(ch2->i_port_id, req->initiator_port_id, 16) + && !memcmp(ch2->t_port_id, req->target_port_id, 16) + && param->port == ch2->sport->port + && param->listen_id == ch2->sport->sdev->cm_id + && ch2->cm_id) { + if (!__srpt_close_ch(ch2)) + continue; + + TRACE_DBG("Found and closed existing channel" + " %s; cm_id = %p", ch2->sess_name, + ch2->cm_id); + + rsp->rsp_flags = + SRP_LOGIN_RSP_MULTICHAN_TERMINATED; + } + } + } else { + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; + } list_add_tail(&ch->list, &sdev->rch_list); + ch->thread = thread; spin_unlock_irq(&sdev->spinlock); - ch->thread = kthread_run(srpt_compl_thread, ch, "srpt_%s", - ch->sport->sdev->device->name); - if (IS_ERR(ch->thread)) { - rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); - PRINT_ERROR("failed to create kernel thread %ld", - PTR_ERR(ch->thread)); - ch->thread = NULL; - goto unreg_ch; - } - ret = srpt_ch_qp_rtr(ch, ch->qp); if (ret) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); @@ -2541,8 +2538,19 @@ rep_param->responder_resources = 4; rep_param->initiator_depth = 4; - ret = ib_send_cm_rep(cm_id, rep_param); - if (ret) { + spin_lock_irq(&sdev->spinlock); + if (ch->state == CH_CONNECTING) + ret = ib_send_cm_rep(cm_id, rep_param); + else + ret = -ECONNABORTED; + spin_unlock_irq(&sdev->spinlock); + + switch (ret) { + case 0: + break; + case -ECONNABORTED: + goto out_keep_cm_id; + default: rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); PRINT_ERROR("sending SRP_LOGIN_REQ response failed" " (error code = %d)", ret); @@ -2561,6 +2569,7 @@ (void *)rej, sizeof *rej); srpt_close_ch(ch); +out_keep_cm_id: /* * Tell the caller not to free cm_id since srpt_free_ch() will do that. */ @@ -2568,10 +2577,6 @@ goto out; unreg_ch: - spin_lock_irq(&sdev->spinlock); - list_del(&ch->list); - spin_unlock_irq(&sdev->spinlock); - scst_unregister_session(ch->scst_sess, true, NULL); destroy_ib: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |