From 08234e3adc7a299c9213bcfa0b5e97c359129670 Mon Sep 17 00:00:00 2001 From: Jörn Engel Date: Wed, 12 Jun 2013 16:27:54 -0400 Subject: 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 Cc: Giridhar Malavali Cc: Chad Dupuis Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/qla_target.c | 151 ++++--------------------------------- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 6 +- 2 files changed, 17 insertions(+), 140 deletions(-) (limited to 'drivers/scsi') 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: return res; } -static bool qlt_check_fcport_exist(struct scsi_qla_host *vha, - struct qla_tgt_sess *sess) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_port_24xx_data *pmap24; - bool res, found = false; - int rc, i; - uint16_t loop_id = 0xFFFF; /* to eliminate compiler's warning */ - uint16_t entries; - void *pmap; - int pmap_len; - fc_port_t *fcport; - int global_resets; - unsigned long flags; - -retry: - global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count); - - rc = qla2x00_get_node_name_list(vha, &pmap, &pmap_len); - if (rc != QLA_SUCCESS) { - res = false; - goto out; - } - - pmap24 = pmap; - entries = pmap_len/sizeof(*pmap24); - - for (i = 0; i < entries; ++i) { - if (!memcmp(sess->port_name, pmap24[i].port_name, WWN_SIZE)) { - loop_id = le16_to_cpu(pmap24[i].loop_id); - found = true; - break; - } - } - - kfree(pmap); - - if (!found) { - res = false; - goto out; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf046, - "qlt_check_fcport_exist(): loop_id %d", loop_id); - - fcport = kzalloc(sizeof(*fcport), GFP_KERNEL); - if (fcport == NULL) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf047, - "qla_target(%d): Allocation of tmp FC port failed", - vha->vp_idx); - res = false; - goto out; - } - - fcport->loop_id = loop_id; - - rc = qla2x00_get_port_database(vha, fcport, 0); - if (rc != QLA_SUCCESS) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf048, - "qla_target(%d): Failed to retrieve fcport " - "information -- get_port_database() returned %x " - "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id); - res = false; - goto out_free_fcport; - } - - if (global_resets != - atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002, - "qla_target(%d): global reset during session discovery" - " (counter was %d, new %d), retrying", - vha->vp_idx, global_resets, - atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)); - goto retry; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003, - "Updating sess %p s_id %x:%x:%x, loop_id %d) to d_id %x:%x:%x, " - "loop_id %d", sess, sess->s_id.b.domain, sess->s_id.b.al_pa, - sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id); - - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id, - (fcport->flags & FCF_CONF_COMP_SUPPORTED)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - res = true; - -out_free_fcport: - kfree(fcport); - -out: - return res; -} - /* ha->hardware_lock supposed to be held on entry */ static void qlt_undelete_sess(struct qla_tgt_sess *sess) { @@ -663,43 +567,13 @@ static void qlt_del_sess_work_fn(struct delayed_work *work) sess = list_entry(tgt->del_sess_list.next, typeof(*sess), del_list_entry); if (time_after_eq(jiffies, sess->expires)) { - bool cancel; - qlt_undelete_sess(sess); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - cancel = qlt_check_fcport_exist(vha, sess); - - if (cancel) { - if (sess->deleted) { - /* - * sess was again deleted while we were - * discovering it - */ - spin_lock_irqsave(&ha->hardware_lock, - flags); - continue; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf049, - "qla_target(%d): cancel deletion of " - "session for port %02x:%02x:%02x:%02x:%02x:" - "%02x:%02x:%02x (loop ID %d), because " - " it isn't deleted by firmware", - vha->vp_idx, sess->port_name[0], - sess->port_name[1], sess->port_name[2], - sess->port_name[3], sess->port_name[4], - sess->port_name[5], sess->port_name[6], - sess->port_name[7], sess->loop_id); - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, - "Timeout: sess %p about to be deleted\n", - sess); - ha->tgt.tgt_ops->shutdown_sess(sess); - ha->tgt.tgt_ops->put_sess(sess); - } - - spin_lock_irqsave(&ha->hardware_lock, flags); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, + "Timeout: sess %p about to be deleted\n", + sess); + ha->tgt.tgt_ops->shutdown_sess(sess); + ha->tgt.tgt_ops->put_sess(sess); } else { schedule_delayed_work(&tgt->sess_del_work, jiffies - sess->expires); @@ -884,9 +758,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) sess->loop_id); sess->local = 0; } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } void 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) /* * Drop extra session reference from qla_tgt_handle_cmd_for_atio*( */ + spin_lock_irqsave(&ha->hardware_lock, flags); ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return; out_term: @@ -2718,9 +2593,9 @@ out_term: spin_lock_irqsave(&ha->hardware_lock, flags); qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); kmem_cache_free(qla_tgt_cmd_cachep, cmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); if (sess) ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } /* ha->hardware_lock supposed to be held on entry */ @@ -4169,16 +4044,16 @@ static void qlt_abort_work(struct qla_tgt *tgt, rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); if (rc != 0) goto out_term; - spin_unlock_irqrestore(&ha->hardware_lock, flags); ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return; out_term: qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); - spin_unlock_irqrestore(&ha->hardware_lock, flags); if (sess) ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } static void qlt_tmr_work(struct qla_tgt *tgt, @@ -4226,16 +4101,16 @@ static void qlt_tmr_work(struct qla_tgt *tgt, rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); if (rc != 0) goto out_term; - spin_unlock_irqrestore(&ha->hardware_lock, flags); ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return; out_term: qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1); - spin_unlock_irqrestore(&ha->hardware_lock, flags); if (sess) ha->tgt.tgt_ops->put_sess(sess); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } static void qlt_sess_work_fn(struct work_struct *work) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 7a3870f385f6..bb7eb909f0b1 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -795,12 +795,14 @@ static void tcm_qla2xxx_put_session(struct se_session *se_sess) static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) { - tcm_qla2xxx_put_session(sess->se_sess); + assert_spin_locked(&sess->vha->hw->hardware_lock); + kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session); } static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess) { - tcm_qla2xxx_shutdown_session(sess->se_sess); + assert_spin_locked(&sess->vha->hw->hardware_lock); + target_sess_cmd_list_set_waiting(sess->se_sess); } static struct se_node_acl *tcm_qla2xxx_make_nodeacl( -- cgit v1.2.3 From b79fafac70fc9bbe640b8193ed772eb850efdfe6 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Wed, 3 Jul 2013 11:22:17 -0400 Subject: target: make queue_tm_rsp() return void The return value wasn't checked by any of the callers. Assuming this is correct behaviour, we can simplify some code by not bothering to generate it. nab: Add srpt_queue_data_in() + srpt_queue_tm_rsp() nops around srpt_queue_response() void return Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/srpt/ib_srpt.c | 27 +++++++++++++++++---------- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 4 +--- drivers/target/iscsi/iscsi_target_configfs.c | 3 +-- drivers/target/loopback/tcm_loop.c | 3 +-- drivers/target/sbp/sbp_target.c | 3 +-- drivers/target/tcm_fc/tcm_fc.h | 2 +- drivers/target/tcm_fc/tfc_cmd.c | 5 ++--- drivers/usb/gadget/tcm_usb_gadget.c | 3 +-- drivers/vhost/scsi.c | 4 ++-- include/target/target_core_fabric.h | 2 +- 10 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 3f3f0416fbdd..653ac6bfc57a 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3011,7 +3011,7 @@ static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status) * Callback function called by the TCM core. Must not block since it can be * invoked on the context of the IB completion handler. */ -static int srpt_queue_response(struct se_cmd *cmd) +static void srpt_queue_response(struct se_cmd *cmd) { struct srpt_rdma_ch *ch; struct srpt_send_ioctx *ioctx; @@ -3022,8 +3022,6 @@ static int srpt_queue_response(struct se_cmd *cmd) int resp_len; u8 srp_tm_status; - ret = 0; - ioctx = container_of(cmd, struct srpt_send_ioctx, cmd); ch = ioctx->ch; BUG_ON(!ch); @@ -3049,7 +3047,7 @@ static int srpt_queue_response(struct se_cmd *cmd) || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) { atomic_inc(&ch->req_lim_delta); srpt_abort_cmd(ioctx); - goto out; + return; } dir = ioctx->cmd.data_direction; @@ -3061,7 +3059,7 @@ static int srpt_queue_response(struct se_cmd *cmd) if (ret) { printk(KERN_ERR "xfer_data failed for tag %llu\n", ioctx->tag); - goto out; + return; } } @@ -3082,9 +3080,17 @@ static int srpt_queue_response(struct se_cmd *cmd) srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); } +} -out: - return ret; +static int srpt_queue_data_in(struct se_cmd *cmd) +{ + srpt_queue_response(cmd); + return 0; +} + +static void srpt_queue_tm_rsp(struct se_cmd *cmd) +{ + srpt_queue_response(cmd); } static int srpt_queue_status(struct se_cmd *cmd) @@ -3097,7 +3103,8 @@ static int srpt_queue_status(struct se_cmd *cmd) (SCF_TRANSPORT_TASK_SENSE | SCF_EMULATED_TASK_SENSE)) WARN_ON(cmd->scsi_status != SAM_STAT_CHECK_CONDITION); ioctx->queue_status_only = true; - return srpt_queue_response(cmd); + srpt_queue_response(cmd); + return 0; } static void srpt_refresh_port_work(struct work_struct *work) @@ -3930,9 +3937,9 @@ static struct target_core_fabric_ops srpt_template = { .set_default_node_attributes = srpt_set_default_node_attrs, .get_task_tag = srpt_get_task_tag, .get_cmd_state = srpt_get_tcm_cmd_state, - .queue_data_in = srpt_queue_response, + .queue_data_in = srpt_queue_data_in, .queue_status = srpt_queue_status, - .queue_tm_rsp = srpt_queue_response, + .queue_tm_rsp = srpt_queue_tm_rsp, /* * Setup function pointers for generic logic in * target_core_fabric_configfs.c diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index bb7eb909f0b1..75caa39b807d 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -699,7 +699,7 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) return qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status); } -static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) +static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) { struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd, @@ -731,8 +731,6 @@ static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) * CTIO response packet. */ qlt_xmit_tm_rsp(mcmd); - - return 0; } /* Local pointer to allocated TCM configfs fabric module */ diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 684d73fcbedf..7d4e19f39fe6 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1790,13 +1790,12 @@ static int lio_queue_status(struct se_cmd *se_cmd) return 0; } -static int lio_queue_tm_rsp(struct se_cmd *se_cmd) +static void lio_queue_tm_rsp(struct se_cmd *se_cmd) { struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); cmd->i_state = ISTATE_SEND_TASKMGTRSP; iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); - return 0; } static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 7c908141cc8a..568ad25f25d3 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -786,7 +786,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd) return 0; } -static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) +static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) { struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr; @@ -796,7 +796,6 @@ static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) */ atomic_set(&tl_tmr->tmr_complete, 1); wake_up(&tl_tmr->tl_tmr_wait); - return 0; } static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index d3536f57444f..e51b09a04d52 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1842,9 +1842,8 @@ static int sbp_queue_status(struct se_cmd *se_cmd) return sbp_send_sense(req); } -static int sbp_queue_tm_rsp(struct se_cmd *se_cmd) +static void sbp_queue_tm_rsp(struct se_cmd *se_cmd) { - return 0; } static int sbp_check_stop_free(struct se_cmd *se_cmd) diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index eea69358ced3..0dd54a44abcf 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -161,7 +161,7 @@ int ft_write_pending(struct se_cmd *); int ft_write_pending_status(struct se_cmd *); u32 ft_get_task_tag(struct se_cmd *); int ft_get_cmd_state(struct se_cmd *); -int ft_queue_tm_resp(struct se_cmd *); +void ft_queue_tm_resp(struct se_cmd *); /* * other internal functions. diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 7b6bb72fa475..0e5a1caed176 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -394,14 +394,14 @@ static void ft_send_tm(struct ft_cmd *cmd) /* * Send status from completed task management request. */ -int ft_queue_tm_resp(struct se_cmd *se_cmd) +void ft_queue_tm_resp(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; if (cmd->aborted) - return 0; + return; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; @@ -421,7 +421,6 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) pr_debug("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); - return 0; } static void ft_send_work(struct work_struct *work); diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 7cacd6ae818e..0ff33396eef3 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1467,9 +1467,8 @@ static int usbg_get_cmd_state(struct se_cmd *se_cmd) return 0; } -static int usbg_queue_tm_rsp(struct se_cmd *se_cmd) +static void usbg_queue_tm_rsp(struct se_cmd *se_cmd) { - return 0; } static const char *usbg_check_wwn(const char *name) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 1e5e82042f84..b35193807f0b 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -528,9 +528,9 @@ static int tcm_vhost_queue_status(struct se_cmd *se_cmd) return 0; } -static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd) +static void tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd) { - return 0; + return; } static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt) diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 1dcce9cc99b9..7a16178424f9 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -61,7 +61,7 @@ struct target_core_fabric_ops { int (*get_cmd_state)(struct se_cmd *); int (*queue_data_in)(struct se_cmd *); int (*queue_status)(struct se_cmd *); - int (*queue_tm_rsp)(struct se_cmd *); + void (*queue_tm_rsp)(struct se_cmd *); /* * fabric module calls for target_core_fabric_configfs.c */ -- cgit v1.2.3