From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch does the initial qla_tgt_sess->sess_kref -> se_sess->sess_kref conversion to use fabric session reference counting. It merges qla_target.c shutdown logic into a single qla_tgt_unreg_sess() call now invoked outside of interrupt handling via system_wq process context in qla_tgt_free_session_done() Also add a struct qla_tgt_func_tmpl->put_sess() call to avoid direct target core symbol usage of target_put_session() in qla_target.c LLD code, and add ->clear_nacl_from_fcport_map() in order to reset se_node_acl pointers in tcm_qla2xxx.ko memory from qla_tgt_unreg_sess() LLD code. With this conversion, the following are now using target_put_session() -> kref_put(se_sess->sess_kref) w/o direct qla_hw_data->hardware_lock access: *) qla_tgt_fc_port_added() libfc callback for session creation *) qla_tgt_handle_cmd_for_atio() path for incoming fast-path I/O *) qla_tgt_abort_work() path for TMR_TASK_ABORT tags *) qla_tgt_tmr_work() path for TMR LUN_RESET So far qla_tgt_sess->se_sess->sess_kref shutdown is working with FC fabric session failures -> delayed session release, explict NodeACL group removal with active session shutdown, and dynamic -> explict NodeACL conversion. Cc: Arun Easi <arun.easi@xxxxxxxxxx> Cc: Roland Dreier <roland@xxxxxxxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Joern Engel <joern@xxxxxxxxx> Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_target.c | 121 +++++++++++++----------------------- drivers/scsi/qla2xxx/qla_target.h | 9 ++- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 71 ++++++++++----------- 3 files changed, 81 insertions(+), 120 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index a2dabb4..a08d4a8 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -329,17 +329,15 @@ void qla_tgt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) } -/* ha->hardware_lock supposed to be held on entry */ -static void qla_tgt_free_session_done(struct qla_tgt_sess *sess) +static void qla_tgt_free_session_done(struct work_struct *work) { - struct qla_tgt *tgt; + struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess, + free_work); + struct qla_tgt *tgt = sess->tgt; struct scsi_qla_host *vha = sess->vha; struct qla_hw_data *ha = vha->hw; - tgt = sess->tgt; - - sess->tearing_down = 1; - + BUG_ON(!tgt); /* * Release the target session for FC Nexus from fabric module code. */ @@ -350,12 +348,6 @@ static void qla_tgt_free_session_done(struct qla_tgt_sess *sess) " sess %p finished\n", sess); kfree(sess); - - if (!tgt) - return; - - ql_dbg(ql_dbg_tgt, vha, 0xe002, "empty(sess_list) %d" - " sess_count %d\n", list_empty(&tgt->sess_list), tgt->sess_count); /* * We need to protect against race, when tgt is freed before or * inside wake_up() @@ -365,48 +357,21 @@ static void qla_tgt_free_session_done(struct qla_tgt_sess *sess) wake_up_all(&tgt->waitQ); } -static void __qla_tgt_unreg_sess(struct kref *kref) -{ - struct qla_tgt_sess *sess = container_of(kref, struct qla_tgt_sess, - sess_kref); - - list_del(&sess->sess_list_entry); - - if (sess->deleted) - list_del(&sess->del_list_entry); - - printk(KERN_INFO "qla_target(%d): %ssession for loop_id %d deleted\n", - sess->vha->vp_idx, sess->local ? "local " : "", - sess->loop_id); - - qla_tgt_free_session_done(sess); -} - /* ha->hardware_lock supposed to be held on entry */ -static void qla_tgt_unreg_sess(struct kref *kref) +void qla_tgt_unreg_sess(struct qla_tgt_sess *sess) { - struct qla_tgt_sess *sess = container_of(kref, struct qla_tgt_sess, - sess_kref); struct scsi_qla_host *vha = sess->vha; - unsigned long flags; - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - __qla_tgt_unreg_sess(kref); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); -} + vha->hw->tgt_ops->clear_nacl_from_fcport_map(sess); -/* ha->hardware_lock supposed to be held on entry */ -int __qla_tgt_sess_put(struct qla_tgt_sess *sess) -{ - return kref_put(&sess->sess_kref, __qla_tgt_unreg_sess); -} -EXPORT_SYMBOL(__qla_tgt_sess_put); + list_del(&sess->sess_list_entry); + if (sess->deleted) + list_del(&sess->del_list_entry); -/* called without ha->hardware_lock held */ -static int qla_tgt_sess_put(struct qla_tgt_sess *sess) -{ - return kref_put(&sess->sess_kref, qla_tgt_unreg_sess); + INIT_WORK(&sess->free_work, qla_tgt_free_session_done); + schedule_work(&sess->free_work); } +EXPORT_SYMBOL(qla_tgt_unreg_sess); /* ha->hardware_lock supposed to be held on entry */ static int qla_tgt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) @@ -701,7 +666,6 @@ static void qla_tgt_del_sess_work_fn(struct delayed_work *work) spin_unlock_irqrestore(&ha->hardware_lock, flags); cancel = qla_tgt_check_fcport_exist(vha, sess); - spin_lock_irqsave(&ha->hardware_lock, flags); if (cancel) { if (sess->deleted) { @@ -709,6 +673,7 @@ static void qla_tgt_del_sess_work_fn(struct delayed_work *work) * sess was again deleted while we were * discovering it */ + spin_lock_irqsave(&ha->hardware_lock, flags); continue; } @@ -724,8 +689,11 @@ static void qla_tgt_del_sess_work_fn(struct delayed_work *work) } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe107, "Timeout: sess %p" " about to be deleted\n", sess); - __qla_tgt_sess_put(sess); + printk("Releasing qla_tgt_del_sess_work_fn w/o hardware_lock >>>>>>>>>>>>\n"); + ha->tgt_ops->put_sess(sess); } + + spin_lock_irqsave(&ha->hardware_lock, flags); } else { schedule_delayed_work(&tgt->sess_del_work, jiffies - sess->expires); @@ -799,13 +767,6 @@ static struct qla_tgt_sess *qla_tgt_create_sess( return NULL; } - /* - * Take two references to ->sess_kref here to handle qla_tgt_sess - * access across ->hardware_lock reaquire. - */ - kref_init(&sess->sess_kref); - kref_get(&sess->sess_kref); - sess->tgt = ha->qla_tgt; sess->vha = vha; sess->s_id = fcport->d_id; @@ -829,6 +790,11 @@ static struct qla_tgt_sess *qla_tgt_create_sess( kfree(sess); return NULL; } + /* + * Take an extra reference to ->sess_kref here to handle qla_tgt_sess + * access across ->hardware_lock reaquire. + */ + kref_get(&sess->se_sess->sess_kref); sess->conf_compl_supported = fcport->conf_compl_supported; BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name)); @@ -885,11 +851,11 @@ void qla_tgt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) mutex_lock(&ha->tgt_mutex); sess = qla_tgt_create_sess(vha, fcport, false); mutex_unlock(&ha->tgt_mutex); - - spin_lock_irqsave(&ha->hardware_lock, flags); /* put the extra creation ref */ if (sess != NULL) - __qla_tgt_sess_put(sess); + if (ha->tgt_ops->put_sess(sess) != 0) + return; + spin_lock_irqsave(&ha->hardware_lock, flags); } else { if (sess->deleted) { qla_tgt_undelete_sess(sess); @@ -2628,7 +2594,7 @@ static void qla_tgt_do_work(struct work_struct *work) /* * Drop extra session reference from qla_tgt_handle_cmd_for_atio*( */ - qla_tgt_sess_put(sess); + ha->tgt_ops->put_sess(sess); return; out_term: @@ -2638,10 +2604,9 @@ out_term: */ spin_lock_irqsave(&ha->hardware_lock, flags); qla_tgt_send_term_exchange(vha, NULL, &cmd->atio, 1); - - if (sess) - __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (sess) + ha->tgt_ops->put_sess(sess); } /* ha->hardware_lock supposed to be held on entry */ @@ -2700,10 +2665,10 @@ static int qla_tgt_handle_cmd_for_atio(struct scsi_qla_host *vha, cmd->conf_compl_supported = sess->conf_compl_supported; /* * Get the extra kref_get() before dropping qla_hw_data->hardware_lock, - * and call qla_tgt_sess_put() -> kref_put() in qla_tgt_do_work() process - * context to drop the extra reference. + * and call kref_put() in qla_tgt_do_work() process context to drop the + * extra reference. */ - kref_get(&sess->sess_kref); + kref_get(&sess->se_sess->sess_kref); out_sched: INIT_WORK(&cmd->work, qla_tgt_do_work); @@ -4017,7 +3982,7 @@ static void qla_tgt_abort_work(struct qla_tgt *tgt, if (sess) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe14c, "sess %p found\n", sess); - kref_get(&sess->sess_kref); + kref_get(&sess->se_sess->sess_kref); } else { spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -4038,17 +4003,17 @@ static void qla_tgt_abort_work(struct qla_tgt *tgt, rc = __qla_tgt_24xx_handle_abts(vha, &prm->abts, sess); if (rc != 0) goto out_term; + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (sess) - __qla_tgt_sess_put(sess); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->tgt_ops->put_sess(sess); return; out_term: qla_tgt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); - if (sess) - __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (sess) + ha->tgt_ops->put_sess(sess); } static void qla_tgt_tmr_work(struct qla_tgt *tgt, @@ -4075,7 +4040,7 @@ static void qla_tgt_tmr_work(struct qla_tgt *tgt, if (sess) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe14c, "sess %p found\n", sess); - kref_get(&sess->sess_kref); + kref_get(&sess->se_sess->sess_kref); } else { spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -4098,17 +4063,17 @@ static void qla_tgt_tmr_work(struct qla_tgt *tgt, rc = qla_tgt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); if (rc != 0) goto out_term; - - if (sess) - __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (sess) + ha->tgt_ops->put_sess(sess); return; out_term: qla_tgt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1); - if (sess) - __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (sess) + ha->tgt_ops->put_sess(sess); } static void qla_tgt_sess_work_fn(struct work_struct *work) diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 1e03d47..f28227a 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -644,6 +644,8 @@ struct qla_tgt_func_tmpl { const uint16_t); struct qla_tgt_sess *(*find_sess_by_s_id)(struct scsi_qla_host *, const uint8_t *); + void (*clear_nacl_from_fcport_map)(struct qla_tgt_sess *); + int (*put_sess)(struct qla_tgt_sess *); }; int qla2x00_wait_for_hba_online(struct scsi_qla_host *); @@ -810,13 +812,12 @@ struct qla_tgt_sess { struct scsi_qla_host *vha; struct qla_tgt *tgt; - struct kref sess_kref; - struct list_head sess_list_entry; unsigned long expires; struct list_head del_list_entry; uint8_t port_name[WWN_SIZE]; + struct work_struct free_work; }; struct qla_tgt_cmd { @@ -924,7 +925,8 @@ extern int qla_tgt_add_target(struct qla_hw_data *, struct scsi_qla_host *); extern int qla_tgt_remove_target(struct qla_hw_data *, struct scsi_qla_host *); extern int qla_tgt_lport_register(struct qla_tgt_func_tmpl *, u64, int (*callback)(struct scsi_qla_host *), void *); -extern void qla_tgt_lport_deregister(struct scsi_qla_host *); +extern void qla_tgt_lport_deregister(struct scsi_qla_host *); +extern void qla_tgt_unreg_sess(struct qla_tgt_sess *); extern void qla_tgt_fc_port_added(struct scsi_qla_host *, fc_port_t *); extern void qla_tgt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *); extern void qla_tgt_set_mode(struct scsi_qla_host *ha); @@ -961,7 +963,6 @@ extern int qla_tgt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); extern void qla_tgt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); extern void qla_tgt_free_mcmd(struct qla_tgt_mgmt_cmd *); extern void qla_tgt_free_cmd(struct qla_tgt_cmd *cmd); -extern int __qla_tgt_sess_put(struct qla_tgt_sess *); extern void qla_tgt_ctio_completion(struct scsi_qla_host *, uint32_t); extern void qla_tgt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *); extern void qla_tgt_enable_vha(struct scsi_qla_host *); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 384914d..cf0d4a5 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -434,39 +434,37 @@ void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd) int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) { struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; + struct scsi_qla_host *vha; + unsigned long flags; + + BUG_ON(!sess); + vha = sess->vha; + + spin_lock_irqsave(&vha->hw->hardware_lock, flags); + sess->tearing_down = 1; + target_splice_sess_cmd_list(se_sess); + spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); - if (!sess) { - pr_err("se_sess->fabric_sess_ptr is NULL\n"); - dump_stack(); - return 0; - } return 1; } -extern int tcm_qla2xxx_clear_nacl_from_fcport_map(struct se_node_acl *); - void tcm_qla2xxx_close_session(struct se_session *se_sess) { - struct se_node_acl *se_nacl = se_sess->se_node_acl; struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; struct scsi_qla_host *vha; unsigned long flags; - if (!sess) { - pr_err("se_sess->fabric_sess_ptr is NULL\n"); - dump_stack(); - return; - } + BUG_ON(!sess); vha = sess->vha; spin_lock_irqsave(&vha->hw->hardware_lock, flags); - tcm_qla2xxx_clear_nacl_from_fcport_map(se_nacl); - __qla_tgt_sess_put(sess); + qla_tgt_unreg_sess(sess); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); } void tcm_qla2xxx_stop_session(struct se_session *se_sess, int sess_sleep , int conn_sleep) { +#if 0 struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; struct scsi_qla_host *vha; unsigned long flags; @@ -481,6 +479,7 @@ void tcm_qla2xxx_stop_session(struct se_session *se_sess, int sess_sleep , int c spin_lock_irqsave(&vha->hw->hardware_lock, flags); tcm_qla2xxx_clear_nacl_from_fcport_map(se_sess->se_node_acl); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); +#endif } void tcm_qla2xxx_reset_nexus(struct se_session *se_sess) @@ -843,9 +842,9 @@ static int tcm_qla2xxx_setup_nacl_from_rport( /* * Expected to be called with struct qla_hw_data->hardware_lock held */ -int tcm_qla2xxx_clear_nacl_from_fcport_map( - struct se_node_acl *se_nacl) +void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess) { + struct se_node_acl *se_nacl = sess->se_sess->se_node_acl; struct se_portal_group *se_tpg = se_nacl->se_tpg; struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; struct tcm_qla2xxx_lport *lport = container_of(se_wwn, @@ -875,8 +874,11 @@ int tcm_qla2xxx_clear_nacl_from_fcport_map( pr_debug("Clearing p->se_nacl to se_nacl: %p for WWNN: 0x%016LX," " port_id: 0x%04x\n", se_nacl, nacl->nport_wwnn, nacl->nport_id); +} - return 0; +int tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) +{ + return target_put_session(sess->se_sess); } static struct se_node_acl *tcm_qla2xxx_make_nodeacl( @@ -1441,6 +1443,9 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) struct tcm_qla2xxx_lport *lport; struct tcm_qla2xxx_nacl *nacl; unsigned char be_sid[3]; + unsigned long flags; + + BUG_ON(in_interrupt()); se_sess = sess->se_sess; if (!se_sess) { @@ -1457,20 +1462,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) dump_stack(); return; } - - target_splice_sess_cmd_list(se_sess); - spin_unlock_irq(&ha->hardware_lock); - target_wait_for_sess_cmds(se_sess, 0); - - spin_lock_irq(&ha->hardware_lock); - - - /* - * Now clear the struct se_node_acl->nacl_sess pointer - */ - transport_deregister_session_configfs(sess->se_sess); - /* * And now clear the se_nacl and session pointers from our HW lport * mappings for fabric S_ID and LOOP_ID. @@ -1480,13 +1472,14 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) be_sid[1] = sess->s_id.b.area; be_sid[2] = sess->s_id.b.al_pa; - tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, - sess, be_sid); - tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, - sess, sess->loop_id); - /* - * Release the FC nexus -> target se_session link now. - */ + spin_lock_irqsave(&ha->hardware_lock, flags); + tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, + sess, be_sid); + tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, + sess, sess->loop_id); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + transport_deregister_session_configfs(sess->se_sess); transport_deregister_session(sess->se_sess); } @@ -1582,6 +1575,8 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = { .check_initiator_node_acl = tcm_qla2xxx_check_initiator_node_acl, .find_sess_by_s_id = tcm_qla2xxx_find_sess_by_s_id, .find_sess_by_loop_id = tcm_qla2xxx_find_sess_by_loop_id, + .clear_nacl_from_fcport_map = tcm_qla2xxx_clear_nacl_from_fcport_map, + .put_sess = tcm_qla2xxx_put_sess, }; static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport) -- 1.7.2.5 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html