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: [<ffffffff81080112>] __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:[<ffffffff81080112>]  [<ffffffff81080112>] __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:
 [<ffffffff81082cae>] ? mark_held_locks+0x6e/0x130
 [<ffffffff810823c5>] lock_acquire+0x95/0x130
 [<ffffffff8103d4ee>] ? try_to_wake_up+0x2e/0x2b0
 [<ffffffff813d618c>] ? _raw_spin_lock_irqsave+0x1c/0x60
 [<ffffffff813d61bb>] _raw_spin_lock_irqsave+0x4b/0x60
 [<ffffffff8103d4ee>] ? try_to_wake_up+0x2e/0x2b0
 [<ffffffff8103d4ee>] try_to_wake_up+0x2e/0x2b0
 [<ffffffff8103d7a5>] wake_up_process+0x15/0x20
 [<ffffffffa0463fda>] srpt_set_ch_state_to_disc+0x5a/0x80 [ib_srpt]
 [<ffffffffa0464016>] __srpt_close_ch+0x16/0xa0 [ib_srpt]
 [<ffffffffa04698e6>] srpt_cm_req_recv+0x806/0xbe0 [ib_srpt]
 [<ffffffffa046ac0d>] srpt_cm_handler+0x7d/0x160 [ib_srpt]
 [<ffffffffa0315c85>] cm_process_work+0x25/0x110 [ib_cm]
 [<ffffffffa031716c>] cm_req_handler+0x67c/0xa00 [ib_cm]
 [<ffffffffa031761d>] cm_work_handler+0x12d/0x1480 [ib_cm]
 [<ffffffff810629c8>] process_one_work+0x198/0x520
 [<ffffffff81062959>] ? process_one_work+0x129/0x520
 [<ffffffffa03174f0>] ? cm_req_handler+0xa00/0xa00 [ib_cm]
 [<ffffffff810646aa>] worker_thread+0x16a/0x350
 [<ffffffff81064540>] ? manage_workers+0x250/0x250
 [<ffffffff81069656>] kthread+0x96/0xa0
 [<ffffffff813e0b74>] kernel_thread_helper+0x4/0x10
 [<ffffffff813d6d9d>] ? retint_restore_args+0xe/0xe
 [<ffffffff810695c0>] ? __init_kthread_worker+0x70/0x70
 [<ffffffff813e0b70>] ? 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  [<ffffffff81080112>] __lock_acquire+0x62/0x1d40
 RSP <ffff8801b50c9950>
CR2: 0000000000000518
---[ end trace efbb413a57b805cb ]---


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4020 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2011-12-20 20:39:20 +00:00
parent 2f6a4f4210
commit 31403966b6
+49 -44
View File
@@ -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: