scsi: qla2xxx: Fix slow mem alloc behind lock

Call Trace:
[<ffffffff81341687>] dump_stack+0x6b/0xa4
[<ffffffff810c3e30>] ? print_irqtrace_events+0xd0/0xe0
[<ffffffff8109e3c3>] ___might_sleep+0x183/0x240
[<ffffffff8109e4d2>] __might_sleep+0x52/0x90
[<ffffffff811fe17b>] kmem_cache_alloc_trace+0x5b/0x300
[<ffffffff810c666b>] ? __lock_acquired+0x30b/0x420
[<ffffffffa0733c28>] qla2x00_alloc_fcport+0x38/0x2a0 [qla2xxx]
[<ffffffffa07217f4>] ? qla2x00_do_work+0x34/0x2b0 [qla2xxx]
[<ffffffff816cc82b>] ? _raw_spin_lock_irqsave+0x7b/0x90
[<ffffffffa072169a>] ? qla24xx_create_new_sess+0x3a/0x160 [qla2xxx]
[<ffffffffa0721723>] qla24xx_create_new_sess+0xc3/0x160 [qla2xxx]
[<ffffffff810c91ed>] ? trace_hardirqs_on+0xd/0x10
[<ffffffffa07218f8>] qla2x00_do_work+0x138/0x2b0 [qla2xxx]

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Quinn Tran and committed by
Martin K. Petersen
b5d15312 1a28faa0

+34 -2
+1
drivers/scsi/qla2xxx/qla_gbl.h
··· 113 113 extern char qla2x00_version_str[]; 114 114 115 115 extern struct kmem_cache *srb_cachep; 116 + extern struct kmem_cache *qla_tgt_plogi_cachep; 116 117 117 118 extern int ql2xlogintimeout; 118 119 extern int qlport_down_retry;
+32 -1
drivers/scsi/qla2xxx/qla_os.c
··· 4677 4677 void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) 4678 4678 { 4679 4679 unsigned long flags; 4680 - fc_port_t *fcport = NULL; 4680 + fc_port_t *fcport = NULL, *tfcp; 4681 4681 struct qlt_plogi_ack_t *pla = 4682 4682 (struct qlt_plogi_ack_t *)e->u.new_sess.pla; 4683 + uint8_t free_fcport = 0; 4683 4684 4684 4685 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 4685 4686 fcport = qla2x00_find_fcport_by_wwpn(vha, e->u.new_sess.port_name, 1); ··· 4695 4694 pla->ref_count--; 4696 4695 } 4697 4696 } else { 4697 + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 4698 4698 fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 4699 4699 if (fcport) { 4700 4700 fcport->d_id = e->u.new_sess.id; ··· 4705 4703 4706 4704 memcpy(fcport->port_name, e->u.new_sess.port_name, 4707 4705 WWN_SIZE); 4706 + } else { 4707 + ql_dbg(ql_dbg_disc, vha, 0xffff, 4708 + "%s %8phC mem alloc fail.\n", 4709 + __func__, e->u.new_sess.port_name); 4710 + 4711 + if (pla) 4712 + kmem_cache_free(qla_tgt_plogi_cachep, pla); 4713 + return; 4714 + } 4715 + 4716 + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 4717 + /* search again to make sure one else got ahead */ 4718 + tfcp = qla2x00_find_fcport_by_wwpn(vha, 4719 + e->u.new_sess.port_name, 1); 4720 + if (tfcp) { 4721 + /* should rarily happen */ 4722 + ql_dbg(ql_dbg_disc, vha, 0xffff, 4723 + "%s %8phC found existing fcport b4 add. DS %d LS %d\n", 4724 + __func__, tfcp->port_name, tfcp->disc_state, 4725 + tfcp->fw_login_state); 4726 + 4727 + free_fcport = 1; 4728 + } else { 4708 4729 list_add_tail(&fcport->list, &vha->vp_fcports); 4709 4730 4710 4731 if (pla) { ··· 4744 4719 qlt_plogi_ack_unref(vha, pla); 4745 4720 else 4746 4721 qla24xx_async_gnl(vha, fcport); 4722 + } 4723 + 4724 + if (free_fcport) { 4725 + qla2x00_free_fcport(fcport); 4726 + if (pla) 4727 + kmem_cache_free(qla_tgt_plogi_cachep, pla); 4747 4728 } 4748 4729 } 4749 4730
+1 -1
drivers/scsi/qla2xxx/qla_target.c
··· 145 145 * Global Variables 146 146 */ 147 147 static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; 148 - static struct kmem_cache *qla_tgt_plogi_cachep; 148 + struct kmem_cache *qla_tgt_plogi_cachep; 149 149 static mempool_t *qla_tgt_mgmt_cmd_mempool; 150 150 static struct workqueue_struct *qla_tgt_wq; 151 151 static DEFINE_MUTEX(qla_tgt_mutex);