From 31403966b617a9651b73458c0d57b82f4b2b2aaf Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 20 Dec 2011 20:39:20 +0000 Subject: [PATCH] ib_srpt: Avoid that very rapidly successive logins from the same initiator cause a crash Fixes this bug report: BUG: unable to handle kernel NULL pointer dereference at 0000000000000518 IP: [] __lock_acquire+0x62/0x1d40 PGD 1b226f067 PUD 1b2241067 PMD 0 Oops: 0000 [#1] SMP CPU 0 Modules linked in: ib_srpt scst_vdisk crc32c libcrc32c scst netconsole configfs snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device af_packet rdma_ucm rdma_cm iw_cm ib_addr ib_ipoib ib_cm ib_sa ib_uverbs ib_umad mlx4_ib ib_mad ib_core microcode cpufreq_co nservative cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf dm_mod snd_hda_codec_hdmi snd_hda_codec_analog snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_timer snd intel_agp sr_mod mlx4_core sg intel_gtt cdrom i2c_i801 agpgart soundcore i2c_co re snd_page_alloc pcspkr button uhci_hcd ehci_hcd sd_mod crc_t10dif usbcore edd ext3 mbcache jbd fan ata_generic ata_piix pata_marvell ahci libahci libata scsi_mod thermal processor thermal_sys hwmon Pid: 4, comm: kworker/0:0 Not tainted 3.1.5-debug+ #1 System manufacturer P5Q DELUXE/P5Q DELUXE RIP: 0010:[] [] __lock_acquire+0x62/0x1d40 RSP: 0018:ffff8801b50c9950 EFLAGS: 00010046 RAX: 0000000000000046 RBX: 0000000000000518 RCX: 0000000000000001 RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000518 RBP: ffff8801b50c9a40 R08: 0000000000000002 R09: 0000000000000001 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801b50aae20 R13: 0000000000000000 R14: 0000000000000002 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8801bfc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000518 CR3: 00000001b1a4d000 CR4: 00000000000406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process kworker/0:0 (pid: 4, threadinfo ffff8801b50c8000, task ffff8801b50aae20) Stack: 0000000000000006 0000000000000001 ffffffff8191ca20 ffff8801b50c99b8 ffffffff81082cae 0000000000000003 ffff8801b50aae20 0000000000000003 0000000000000002 0000000000000000 ffff8801b50c9aa0 0000000000000046 Call Trace: [] ? mark_held_locks+0x6e/0x130 [] lock_acquire+0x95/0x130 [] ? try_to_wake_up+0x2e/0x2b0 [] ? _raw_spin_lock_irqsave+0x1c/0x60 [] _raw_spin_lock_irqsave+0x4b/0x60 [] ? try_to_wake_up+0x2e/0x2b0 [] try_to_wake_up+0x2e/0x2b0 [] wake_up_process+0x15/0x20 [] srpt_set_ch_state_to_disc+0x5a/0x80 [ib_srpt] [] __srpt_close_ch+0x16/0xa0 [ib_srpt] [] srpt_cm_req_recv+0x806/0xbe0 [ib_srpt] [] srpt_cm_handler+0x7d/0x160 [ib_srpt] [] cm_process_work+0x25/0x110 [ib_cm] [] cm_req_handler+0x67c/0xa00 [ib_cm] [] cm_work_handler+0x12d/0x1480 [ib_cm] [] process_one_work+0x198/0x520 [] ? process_one_work+0x129/0x520 [] ? cm_req_handler+0xa00/0xa00 [ib_cm] [] worker_thread+0x16a/0x350 [] ? manage_workers+0x250/0x250 [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 [] ? retint_restore_args+0xe/0xe [] ? __init_kthread_worker+0x70/0x70 [] ? gs_change+0xb/0xb Code: 25 00 b6 00 00 4c 89 7d f8 85 c9 48 89 fb 45 0f 45 f0 41 89 f5 85 d2 0f 84 44 0d 00 00 8b 05 5a 3a 6f 00 85 c0 0f 84 c6 01 00 00 8b 03 ba 01 00 00 00 48 3d c0 75 7b 81 44 0f 44 f2 41 83 fd RIP [] __lock_acquire+0x62/0x1d40 RSP CR2: 0000000000000518 ---[ end trace efbb413a57b805cb ]--- git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4020 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- srpt/src/ib_srpt.c | 93 ++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 061af544b..2cf14d4cb 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -2313,7 +2313,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, 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 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, 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 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto destroy_ib; } - spin_lock_irq(&sdev->spinlock); - list_add_tail(&ch->list, &sdev->rch_list); - 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)) { + 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)); - ch->thread = NULL; + 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); + ret = srpt_ch_qp_rtr(ch, ch->qp); if (ret) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); @@ -2541,8 +2538,19 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, 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 @@ reject_and_release: (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 @@ reject_and_release: 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: