aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2018-02-22 03:49:35 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2018-03-01 20:16:50 -0500
commit1c6cacf4ea6c04a58a0e3057f5ed60c24a4ffeff (patch)
tree63796fdf986b01e35d7c872c83657e7873a2dd11
parent1514839b366417934e2f1328edb50ed1e8a719f5 (diff)
scsi: qla2xxx: Fixup locking for session deletion
Commit d8630bb95f46 ('Serialize session deletion by using work_lock') tries to fixup a deadlock when deleting sessions, but fails to take into account the locking rules. This patch resolves the situation by introducing a separate lock for processing the GNLIST response, and ensures that sess_lock is released before calling qlt_schedule_sess_delete(). Cc: Himanshu Madhani <himanshu.madhani@cavium.com> Cc: Quinn Tran <quinn.tran@cavium.com> Fixes: d8630bb95f46 ("scsi: qla2xxx: Serialize session deletion by using work_lock") Signed-off-by: Hannes Reinecke <hare@suse.com> Acked-by: Himanshu Madhani <himanshu.madhani@cavium.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c24
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c17
4 files changed, 29 insertions, 23 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index be7d6824581a..3ca4b6a5eddd 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -261,9 +261,9 @@
261struct name_list_extended { 261struct name_list_extended {
262 struct get_name_list_extended *l; 262 struct get_name_list_extended *l;
263 dma_addr_t ldma; 263 dma_addr_t ldma;
264 struct list_head fcports; /* protect by sess_list */ 264 struct list_head fcports;
265 spinlock_t fcports_lock;
265 u32 size; 266 u32 size;
266 u8 sent;
267}; 267};
268/* 268/*
269 * Timeout timer counts in seconds 269 * Timeout timer counts in seconds
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 04870621e712..cacf2ccc081b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -643,8 +643,7 @@ qla24xx_async_gnl_sp_done(void *s, int res)
643 (loop_id & 0x7fff)); 643 (loop_id & 0x7fff));
644 } 644 }
645 645
646 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 646 spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
647 vha->gnl.sent = 0;
648 647
649 INIT_LIST_HEAD(&h); 648 INIT_LIST_HEAD(&h);
650 fcport = tf = NULL; 649 fcport = tf = NULL;
@@ -653,12 +652,16 @@ qla24xx_async_gnl_sp_done(void *s, int res)
653 652
654 list_for_each_entry_safe(fcport, tf, &h, gnl_entry) { 653 list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
655 list_del_init(&fcport->gnl_entry); 654 list_del_init(&fcport->gnl_entry);
655 spin_lock(&vha->hw->tgt.sess_lock);
656 fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); 656 fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
657 spin_unlock(&vha->hw->tgt.sess_lock);
657 ea.fcport = fcport; 658 ea.fcport = fcport;
658 659
659 qla2x00_fcport_event_handler(vha, &ea); 660 qla2x00_fcport_event_handler(vha, &ea);
660 } 661 }
662 spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
661 663
664 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
662 /* create new fcport if fw has knowledge of new sessions */ 665 /* create new fcport if fw has knowledge of new sessions */
663 for (i = 0; i < n; i++) { 666 for (i = 0; i < n; i++) {
664 port_id_t id; 667 port_id_t id;
@@ -710,18 +713,21 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
710 ql_dbg(ql_dbg_disc, vha, 0x20d9, 713 ql_dbg(ql_dbg_disc, vha, 0x20d9,
711 "Async-gnlist WWPN %8phC \n", fcport->port_name); 714 "Async-gnlist WWPN %8phC \n", fcport->port_name);
712 715
713 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 716 spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
717 if (!list_empty(&fcport->gnl_entry)) {
718 spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
719 rval = QLA_SUCCESS;
720 goto done;
721 }
722
723 spin_lock(&vha->hw->tgt.sess_lock);
714 fcport->disc_state = DSC_GNL; 724 fcport->disc_state = DSC_GNL;
715 fcport->last_rscn_gen = fcport->rscn_gen; 725 fcport->last_rscn_gen = fcport->rscn_gen;
716 fcport->last_login_gen = fcport->login_gen; 726 fcport->last_login_gen = fcport->login_gen;
727 spin_unlock(&vha->hw->tgt.sess_lock);
717 728
718 list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports); 729 list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports);
719 if (vha->gnl.sent) { 730 spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
720 spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
721 return QLA_SUCCESS;
722 }
723 vha->gnl.sent = 1;
724 spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
725 731
726 sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 732 sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
727 if (!sp) 733 if (!sp)
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index afcb5567998a..585f37155f29 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4577,6 +4577,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
4577 4577
4578 spin_lock_init(&vha->work_lock); 4578 spin_lock_init(&vha->work_lock);
4579 spin_lock_init(&vha->cmd_list_lock); 4579 spin_lock_init(&vha->cmd_list_lock);
4580 spin_lock_init(&vha->gnl.fcports_lock);
4580 init_waitqueue_head(&vha->fcport_waitQ); 4581 init_waitqueue_head(&vha->fcport_waitQ);
4581 init_waitqueue_head(&vha->vref_waitq); 4582 init_waitqueue_head(&vha->vref_waitq);
4582 4583
@@ -4877,6 +4878,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
4877 } 4878 }
4878 qlt_plogi_ack_unref(vha, pla); 4879 qlt_plogi_ack_unref(vha, pla);
4879 } else { 4880 } else {
4881 fc_port_t *dfcp = NULL;
4882
4880 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 4883 spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
4881 tfcp = qla2x00_find_fcport_by_nportid(vha, 4884 tfcp = qla2x00_find_fcport_by_nportid(vha,
4882 &e->u.new_sess.id, 1); 4885 &e->u.new_sess.id, 1);
@@ -4899,11 +4902,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
4899 default: 4902 default:
4900 fcport->login_pause = 1; 4903 fcport->login_pause = 1;
4901 tfcp->conflict = fcport; 4904 tfcp->conflict = fcport;
4902 qlt_schedule_sess_for_deletion(tfcp); 4905 dfcp = tfcp;
4903 break; 4906 break;
4904 } 4907 }
4905 } 4908 }
4906 spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 4909 spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
4910 if (dfcp)
4911 qlt_schedule_sess_for_deletion(tfcp);
4907 4912
4908 wwn = wwn_to_u64(fcport->node_name); 4913 wwn = wwn_to_u64(fcport->node_name);
4909 4914
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 896b2d8bd803..b49ac85f3de2 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1224,10 +1224,10 @@ static void qla24xx_chk_fcp_state(struct fc_port *sess)
1224 } 1224 }
1225} 1225}
1226 1226
1227/* ha->tgt.sess_lock supposed to be held on entry */
1228void qlt_schedule_sess_for_deletion(struct fc_port *sess) 1227void qlt_schedule_sess_for_deletion(struct fc_port *sess)
1229{ 1228{
1230 struct qla_tgt *tgt = sess->tgt; 1229 struct qla_tgt *tgt = sess->tgt;
1230 struct qla_hw_data *ha = sess->vha->hw;
1231 unsigned long flags; 1231 unsigned long flags;
1232 1232
1233 if (sess->disc_state == DSC_DELETE_PEND) 1233 if (sess->disc_state == DSC_DELETE_PEND)
@@ -1244,16 +1244,16 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
1244 return; 1244 return;
1245 } 1245 }
1246 1246
1247 spin_lock_irqsave(&ha->tgt.sess_lock, flags);
1247 if (sess->deleted == QLA_SESS_DELETED) 1248 if (sess->deleted == QLA_SESS_DELETED)
1248 sess->logout_on_delete = 0; 1249 sess->logout_on_delete = 0;
1249 1250
1250 spin_lock_irqsave(&sess->vha->work_lock, flags);
1251 if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { 1251 if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
1252 spin_unlock_irqrestore(&sess->vha->work_lock, flags); 1252 spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
1253 return; 1253 return;
1254 } 1254 }
1255 sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; 1255 sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
1256 spin_unlock_irqrestore(&sess->vha->work_lock, flags); 1256 spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
1257 1257
1258 sess->disc_state = DSC_DELETE_PEND; 1258 sess->disc_state = DSC_DELETE_PEND;
1259 1259
@@ -1262,13 +1262,10 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
1262 ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, 1262 ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
1263 "Scheduling sess %p for deletion\n", sess); 1263 "Scheduling sess %p for deletion\n", sess);
1264 1264
1265 /* use cancel to push work element through before re-queue */
1266 cancel_work_sync(&sess->del_work);
1267 INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn); 1265 INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn);
1268 queue_work(sess->vha->hw->wq, &sess->del_work); 1266 WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work));
1269} 1267}
1270 1268
1271/* ha->tgt.sess_lock supposed to be held on entry */
1272static void qlt_clear_tgt_db(struct qla_tgt *tgt) 1269static void qlt_clear_tgt_db(struct qla_tgt *tgt)
1273{ 1270{
1274 struct fc_port *sess; 1271 struct fc_port *sess;
@@ -1451,8 +1448,8 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
1451 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); 1448 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess);
1452 1449
1453 sess->local = 1; 1450 sess->local = 1;
1454 qlt_schedule_sess_for_deletion(sess);
1455 spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 1451 spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
1452 qlt_schedule_sess_for_deletion(sess);
1456} 1453}
1457 1454
1458static inline int test_tgt_sess_count(struct qla_tgt *tgt) 1455static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -1512,10 +1509,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
1512 * Lock is needed, because we still can get an incoming packet. 1509 * Lock is needed, because we still can get an incoming packet.
1513 */ 1510 */
1514 mutex_lock(&vha->vha_tgt.tgt_mutex); 1511 mutex_lock(&vha->vha_tgt.tgt_mutex);
1515 spin_lock_irqsave(&ha->tgt.sess_lock, flags);
1516 tgt->tgt_stop = 1; 1512 tgt->tgt_stop = 1;
1517 qlt_clear_tgt_db(tgt); 1513 qlt_clear_tgt_db(tgt);
1518 spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
1519 mutex_unlock(&vha->vha_tgt.tgt_mutex); 1514 mutex_unlock(&vha->vha_tgt.tgt_mutex);
1520 mutex_unlock(&qla_tgt_mutex); 1515 mutex_unlock(&qla_tgt_mutex);
1521 1516