From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch adds proper qla_tgt_sess->sess_kref operation for qla_tgt_sess reference and two flavours of qla_tgt_unreg_sess() in order to have a qla_hw_data->hardware_lock lock-less method to execute qla_tgt_cmd in qla_tgt_do_work() process context. It also convert existing ->hardware_lock held qla_tgt_sess_put() callers to use __qla_tgt_sess_put() Cc: Christoph Hellwig <hch@xxxxxx> Cc: Roland Dreier <roland@xxxxxxxxxxxxxxx> Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_target.c | 85 ++++++++++++----------- drivers/scsi/qla2xxx/qla_target.h | 4 +- drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c | 2 +- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 9496c6f..3a9aa44 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -125,27 +125,6 @@ static LIST_HEAD(qla_tgt_glist); */ extern request_t *qla2x00_req_pkt(struct scsi_qla_host *); -/* ha->hardware_lock supposed to be held on entry */ -static inline void qla_tgt_sess_get(struct qla_tgt_sess *sess) -{ - sess->sess_ref++; - ql_dbg(ql_dbg_tgt, sess->vha, 0xe000, "sess %p, new sess_ref %d\n", - sess, sess->sess_ref); -} - -/* ha->hardware_lock supposed to be held on entry */ -void qla_tgt_sess_put(struct qla_tgt_sess *sess) -{ - ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, "sess %p, new sess_ref %d\n", - sess, sess->sess_ref-1); - BUG_ON(sess->sess_ref == 0); - - sess->sess_ref--; - if (sess->sess_ref == 0) - qla_tgt_unreg_sess(sess); -} -EXPORT_SYMBOL(qla_tgt_sess_put); - /* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */ static struct qla_tgt_sess *qla_tgt_find_sess_by_port_name( struct qla_tgt *tgt, @@ -408,13 +387,10 @@ static void qla_tgt_free_session_done(struct qla_tgt_sess *sess) wake_up_all(&tgt->waitQ); } -/* ha->hardware_lock supposed to be held on entry */ -static int qla_tgt_unreg_sess(struct qla_tgt_sess *sess) +static void __qla_tgt_unreg_sess(struct kref *kref) { - int res = 1; - - BUG_ON(sess == NULL); - BUG_ON(sess->sess_ref != 0); + struct qla_tgt_sess *sess = container_of(kref, struct qla_tgt_sess, + sess_kref); list_del(&sess->sess_list_entry); @@ -426,8 +402,32 @@ static int qla_tgt_unreg_sess(struct qla_tgt_sess *sess) sess->loop_id); qla_tgt_free_session_done(sess); +} - return res; +/* ha->hardware_lock supposed to be held on entry */ +static void qla_tgt_unreg_sess(struct kref *kref) +{ + 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); +} + +/* 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); + +/* 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); } /* ha->hardware_lock supposed to be held on entry */ @@ -783,7 +783,7 @@ 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); + __qla_tgt_sess_put(sess); } } else { schedule_delayed_work(&tgt->sess_del_work, @@ -858,11 +858,15 @@ 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->sess_ref = 2; /* plus 1 extra ref, see above */ sess->tgt = ha->qla_tgt; sess->vha = vha; - sess->s_id = fcport->d_id; sess->loop_id = fcport->loop_id; sess->local = local; @@ -942,8 +946,9 @@ void qla_tgt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) 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); /* put the extra creation ref */ + __qla_tgt_sess_put(sess); } else { if (sess->deleted) { qla_tgt_undelete_sess(sess); @@ -4589,7 +4594,7 @@ static void qla_tgt_exec_cmd_work(struct work_struct *work) if (sess) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe14c, "sess %p found\n", sess); - qla_tgt_sess_get(sess); + kref_get(&sess->sess_kref); } else { spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -4674,7 +4679,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); - qla_tgt_sess_get(sess); + kref_get(&sess->sess_kref); } else { spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -4700,8 +4705,7 @@ static void qla_tgt_abort_work(struct qla_tgt *tgt, goto out_term; if (sess) - qla_tgt_sess_put(sess); - + __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); return; @@ -4715,8 +4719,7 @@ out_term: } if (sess) - qla_tgt_sess_put(sess); - + __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); } @@ -4748,7 +4751,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); - qla_tgt_sess_get(sess); + kref_get(&sess->sess_kref); } else { spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -4784,7 +4787,7 @@ static void qla_tgt_tmr_work(struct qla_tgt *tgt, goto out_term; if (sess) - qla_tgt_sess_put(sess); + __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); return; @@ -4795,7 +4798,7 @@ out_term: qla_tgt_send_notify_ack(vha, &prm->tm_iocb, 0, 0, 0, 0, 0, 0); if (sess) - qla_tgt_sess_put(sess); + __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&ha->hardware_lock, flags); } diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index e868490..a9032d6 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -905,7 +905,7 @@ struct qla_tgt_sess { struct scsi_qla_host *vha; struct qla_tgt *tgt; - int sess_ref; /* protected by hardware_lock */ + struct kref sess_kref; struct list_head sess_list_entry; unsigned long expires; @@ -1123,7 +1123,7 @@ 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 void qla_tgt_sess_put(struct qla_tgt_sess *); +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/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c index 8fe8710..c1080e2 100644 --- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c +++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c @@ -481,7 +481,7 @@ void tcm_qla2xxx_close_session(struct se_session *se_sess) spin_lock_irqsave(&vha->hw->hardware_lock, flags); tcm_qla2xxx_clear_nacl_from_fcport_map(se_nacl); - qla_tgt_sess_put(sess); + __qla_tgt_sess_put(sess); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); } -- 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