aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_target.c
diff options
context:
space:
mode:
authorJörn Engel <joern@logfs.org>2013-06-12 16:27:54 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-06-20 17:10:48 -0400
commit08234e3adc7a299c9213bcfa0b5e97c359129670 (patch)
tree0caae34a966145ca746550421ae50909c1a23c24 /drivers/scsi/qla2xxx/qla_target.c
parent084ed45b3846ffb803a6cd6d631c1723e77689e0 (diff)
qla_target: remove qlt_check_fcport_exist
Comment from original 2012 patch: In all our testing this function has never returned true. However, the dropping of hardware_lock necessary to call this function seems to cause a use-after-free we manage to hit rather frequently. Given this cost-benefit ratio, I'm willing to remove some 100 lines of code. And since the same problem exists around shutdown_sess and put_sess, this patch changes them from taking the hardware_lock to requiring the hardware_lock to be taken. In most cases the caller already had the lock and had to drop it for the called method to reacquire it. At best that hurts performance and in rare instances it causes races with fatal consequences. We dropped the original 2012 patch when upgrading our kernel and it took us nearly half a year to discover we still need it. (nab: Fix qla_tgt_sess reference in tcm_qla2xxx_put_sess) Signed-off-by: Joern Engel <joern@logfs.org> Cc: Giridhar Malavali <giridhar.malavali@qlogic.com> Cc: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_target.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c151
1 files changed, 13 insertions, 138 deletions
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index fcdc22306cab..83a8f7a9ec76 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -544,102 +544,6 @@ out_free_id_list:
544 return res; 544 return res;
545} 545}
546 546
547static bool qlt_check_fcport_exist(struct scsi_qla_host *vha,
548 struct qla_tgt_sess *sess)
549{
550 struct qla_hw_data *ha = vha->hw;
551 struct qla_port_24xx_data *pmap24;
552 bool res, found = false;
553 int rc, i;
554 uint16_t loop_id = 0xFFFF; /* to eliminate compiler's warning */
555 uint16_t entries;
556 void *pmap;
557 int pmap_len;
558 fc_port_t *fcport;
559 int global_resets;
560 unsigned long flags;
561
562retry:
563 global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count);
564
565 rc = qla2x00_get_node_name_list(vha, &pmap, &pmap_len);
566 if (rc != QLA_SUCCESS) {
567 res = false;
568 goto out;
569 }
570
571 pmap24 = pmap;
572 entries = pmap_len/sizeof(*pmap24);
573
574 for (i = 0; i < entries; ++i) {
575 if (!memcmp(sess->port_name, pmap24[i].port_name, WWN_SIZE)) {
576 loop_id = le16_to_cpu(pmap24[i].loop_id);
577 found = true;
578 break;
579 }
580 }
581
582 kfree(pmap);
583
584 if (!found) {
585 res = false;
586 goto out;
587 }
588
589 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf046,
590 "qlt_check_fcport_exist(): loop_id %d", loop_id);
591
592 fcport = kzalloc(sizeof(*fcport), GFP_KERNEL);
593 if (fcport == NULL) {
594 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf047,
595 "qla_target(%d): Allocation of tmp FC port failed",
596 vha->vp_idx);
597 res = false;
598 goto out;
599 }
600
601 fcport->loop_id = loop_id;
602
603 rc = qla2x00_get_port_database(vha, fcport, 0);
604 if (rc != QLA_SUCCESS) {
605 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf048,
606 "qla_target(%d): Failed to retrieve fcport "
607 "information -- get_port_database() returned %x "
608 "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id);
609 res = false;
610 goto out_free_fcport;
611 }
612
613 if (global_resets !=
614 atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) {
615 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002,
616 "qla_target(%d): global reset during session discovery"
617 " (counter was %d, new %d), retrying",
618 vha->vp_idx, global_resets,
619 atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count));
620 goto retry;
621 }
622
623 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003,
624 "Updating sess %p s_id %x:%x:%x, loop_id %d) to d_id %x:%x:%x, "
625 "loop_id %d", sess, sess->s_id.b.domain, sess->s_id.b.al_pa,
626 sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain,
627 fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id);
628
629 spin_lock_irqsave(&ha->hardware_lock, flags);
630 ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
631 (fcport->flags & FCF_CONF_COMP_SUPPORTED));
632 spin_unlock_irqrestore(&ha->hardware_lock, flags);
633
634 res = true;
635
636out_free_fcport:
637 kfree(fcport);
638
639out:
640 return res;
641}
642
643/* ha->hardware_lock supposed to be held on entry */ 547/* ha->hardware_lock supposed to be held on entry */
644static void qlt_undelete_sess(struct qla_tgt_sess *sess) 548static void qlt_undelete_sess(struct qla_tgt_sess *sess)
645{ 549{
@@ -663,43 +567,13 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
663 sess = list_entry(tgt->del_sess_list.next, typeof(*sess), 567 sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
664 del_list_entry); 568 del_list_entry);
665 if (time_after_eq(jiffies, sess->expires)) { 569 if (time_after_eq(jiffies, sess->expires)) {
666 bool cancel;
667
668 qlt_undelete_sess(sess); 570 qlt_undelete_sess(sess);
669 571
670 spin_unlock_irqrestore(&ha->hardware_lock, flags); 572 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
671 cancel = qlt_check_fcport_exist(vha, sess); 573 "Timeout: sess %p about to be deleted\n",
672 574 sess);
673 if (cancel) { 575 ha->tgt.tgt_ops->shutdown_sess(sess);
674 if (sess->deleted) { 576 ha->tgt.tgt_ops->put_sess(sess);
675 /*
676 * sess was again deleted while we were
677 * discovering it
678 */
679 spin_lock_irqsave(&ha->hardware_lock,
680 flags);
681 continue;
682 }
683
684 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf049,
685 "qla_target(%d): cancel deletion of "
686 "session for port %02x:%02x:%02x:%02x:%02x:"
687 "%02x:%02x:%02x (loop ID %d), because "
688 " it isn't deleted by firmware",
689 vha->vp_idx, sess->port_name[0],
690 sess->port_name[1], sess->port_name[2],
691 sess->port_name[3], sess->port_name[4],
692 sess->port_name[5], sess->port_name[6],
693 sess->port_name[7], sess->loop_id);
694 } else {
695 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
696 "Timeout: sess %p about to be deleted\n",
697 sess);
698 ha->tgt.tgt_ops->shutdown_sess(sess);
699 ha->tgt.tgt_ops->put_sess(sess);
700 }
701
702 spin_lock_irqsave(&ha->hardware_lock, flags);
703 } else { 577 } else {
704 schedule_delayed_work(&tgt->sess_del_work, 578 schedule_delayed_work(&tgt->sess_del_work,
705 jiffies - sess->expires); 579 jiffies - sess->expires);
@@ -884,9 +758,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
884 sess->loop_id); 758 sess->loop_id);
885 sess->local = 0; 759 sess->local = 0;
886 } 760 }
887 spin_unlock_irqrestore(&ha->hardware_lock, flags);
888
889 ha->tgt.tgt_ops->put_sess(sess); 761 ha->tgt.tgt_ops->put_sess(sess);
762 spin_unlock_irqrestore(&ha->hardware_lock, flags);
890} 763}
891 764
892void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport) 765void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
@@ -2706,7 +2579,9 @@ static void qlt_do_work(struct work_struct *work)
2706 /* 2579 /*
2707 * Drop extra session reference from qla_tgt_handle_cmd_for_atio*( 2580 * Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
2708 */ 2581 */
2582 spin_lock_irqsave(&ha->hardware_lock, flags);
2709 ha->tgt.tgt_ops->put_sess(sess); 2583 ha->tgt.tgt_ops->put_sess(sess);
2584 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2710 return; 2585 return;
2711 2586
2712out_term: 2587out_term:
@@ -2718,9 +2593,9 @@ out_term:
2718 spin_lock_irqsave(&ha->hardware_lock, flags); 2593 spin_lock_irqsave(&ha->hardware_lock, flags);
2719 qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); 2594 qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
2720 kmem_cache_free(qla_tgt_cmd_cachep, cmd); 2595 kmem_cache_free(qla_tgt_cmd_cachep, cmd);
2721 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2722 if (sess) 2596 if (sess)
2723 ha->tgt.tgt_ops->put_sess(sess); 2597 ha->tgt.tgt_ops->put_sess(sess);
2598 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2724} 2599}
2725 2600
2726/* ha->hardware_lock supposed to be held on entry */ 2601/* ha->hardware_lock supposed to be held on entry */
@@ -4169,16 +4044,16 @@ static void qlt_abort_work(struct qla_tgt *tgt,
4169 rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); 4044 rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
4170 if (rc != 0) 4045 if (rc != 0)
4171 goto out_term; 4046 goto out_term;
4172 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4173 4047
4174 ha->tgt.tgt_ops->put_sess(sess); 4048 ha->tgt.tgt_ops->put_sess(sess);
4049 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4175 return; 4050 return;
4176 4051
4177out_term: 4052out_term:
4178 qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); 4053 qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
4179 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4180 if (sess) 4054 if (sess)
4181 ha->tgt.tgt_ops->put_sess(sess); 4055 ha->tgt.tgt_ops->put_sess(sess);
4056 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4182} 4057}
4183 4058
4184static void qlt_tmr_work(struct qla_tgt *tgt, 4059static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -4226,16 +4101,16 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
4226 rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); 4101 rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
4227 if (rc != 0) 4102 if (rc != 0)
4228 goto out_term; 4103 goto out_term;
4229 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4230 4104
4231 ha->tgt.tgt_ops->put_sess(sess); 4105 ha->tgt.tgt_ops->put_sess(sess);
4106 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4232 return; 4107 return;
4233 4108
4234out_term: 4109out_term:
4235 qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1); 4110 qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
4236 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4237 if (sess) 4111 if (sess)
4238 ha->tgt.tgt_ops->put_sess(sess); 4112 ha->tgt.tgt_ops->put_sess(sess);
4113 spin_unlock_irqrestore(&ha->hardware_lock, flags);
4239} 4114}
4240 4115
4241static void qlt_sess_work_fn(struct work_struct *work) 4116static void qlt_sess_work_fn(struct work_struct *work)