* [PATCH 0/7] series to fix qla2xxx use-after-free
@ 2012-07-16 18:04 Roland Dreier
2012-07-16 18:04 ` [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down Roland Dreier
` (6 more replies)
0 siblings, 7 replies; 25+ messages in thread
From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw)
To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi
From: Roland Dreier <roland@purestorage.com>
Hi Nic,
Here's a series that's fundamentally about fixing a use-after-free in
qla_target code. It ends up being seven patches because I wanted to
make each step easy to review, and several of these are just cleanups
that stand on their own.
We have a few more qla2xxx-related fixes that I need to clean up and
merge with the latest. I'll send them soon.
Roland Dreier (7):
qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down
target: Un-export target_get_sess_cmd()
sbp-target: Consolidate duplicated error path code in
sbp_handle_command()
target: Allow for target_submit_cmd() returning errors
target: Check sess_tearing_down in target_get_sess_cmd()
qla2xxx: Remove racy, now-redundant check of sess_tearing_down
target: Remove se_session.sess_wait_list
drivers/scsi/qla2xxx/qla_target.c | 16 ++--------
drivers/scsi/qla2xxx/qla_target.h | 1 -
drivers/scsi/qla2xxx/tcm_qla2xxx.c | 10 +++---
drivers/target/sbp/sbp_target.c | 36 ++++++++++-----------
drivers/target/target_core_transport.c | 55 ++++++++++++++++++++------------
drivers/target/tcm_fc/tfc_cmd.c | 8 +++--
drivers/usb/gadget/tcm_usb_gadget.c | 20 +++++-------
include/target/target_core_base.h | 1 -
include/target/target_core_fabric.h | 5 ++-
9 files changed, 73 insertions(+), 79 deletions(-)
--
1.7.10.4
^ permalink raw reply [flat|nested] 25+ messages in thread* [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 22:52 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 2/7] target: Un-export target_get_sess_cmd() Roland Dreier ` (5 subsequent siblings) 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi From: Roland Dreier <roland@purestorage.com> The only place that sets qla_tgt_sess.tearing_down calls target_splice_sess_cmd_list() immediately afterwards, without dropping the lock it holds. That function sets se_session.sess_tearing_down, so we can get rid of the qla_target-specific flag, and in the one place that looks at the qla_tgt_sess.tearing_down flag just test se_session.sess_tearing_down instead. Cc: Chad Dupuis <chad.dupuis@qlogic.com> Cc: Arun Easi <arun.easi@qlogic.com> Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/scsi/qla2xxx/qla_target.c | 2 +- drivers/scsi/qla2xxx/qla_target.h | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 77759c7..87b5a330 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2644,7 +2644,7 @@ static void qlt_do_work(struct work_struct *work) sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); if (sess) { - if (unlikely(sess->tearing_down)) { + if (unlikely(sess->se_sess->sess_tearing_down)) { sess = NULL; spin_unlock_irqrestore(&ha->hardware_lock, flags); goto out_term; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 9f9ef16..07aa265 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -813,7 +813,6 @@ struct qla_tgt_sess { unsigned int conf_compl_supported:1; unsigned int deleted:1; unsigned int local:1; - unsigned int tearing_down:1; struct se_session *se_sess; struct scsi_qla_host *vha; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 6e64314..3cb2b97 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -466,7 +466,6 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_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); -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down 2012-07-16 18:04 ` [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down Roland Dreier @ 2012-07-16 22:52 ` Nicholas A. Bellinger 0 siblings, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 22:52 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > The only place that sets qla_tgt_sess.tearing_down calls > target_splice_sess_cmd_list() immediately afterwards, without dropping > the lock it holds. That function sets se_session.sess_tearing_down, > so we can get rid of the qla_target-specific flag, and in the one > place that looks at the qla_tgt_sess.tearing_down flag just test > se_session.sess_tearing_down instead. > Looks fine. Applied to for-next. Thanks Roland! > Cc: Chad Dupuis <chad.dupuis@qlogic.com> > Cc: Arun Easi <arun.easi@qlogic.com> > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/scsi/qla2xxx/qla_target.c | 2 +- > drivers/scsi/qla2xxx/qla_target.h | 1 - > drivers/scsi/qla2xxx/tcm_qla2xxx.c | 1 - > 3 files changed, 1 insertion(+), 3 deletions(-) > > diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c > index 77759c7..87b5a330 100644 > --- a/drivers/scsi/qla2xxx/qla_target.c > +++ b/drivers/scsi/qla2xxx/qla_target.c > @@ -2644,7 +2644,7 @@ static void qlt_do_work(struct work_struct *work) > sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, > atio->u.isp24.fcp_hdr.s_id); > if (sess) { > - if (unlikely(sess->tearing_down)) { > + if (unlikely(sess->se_sess->sess_tearing_down)) { > sess = NULL; > spin_unlock_irqrestore(&ha->hardware_lock, flags); > goto out_term; > diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h > index 9f9ef16..07aa265 100644 > --- a/drivers/scsi/qla2xxx/qla_target.h > +++ b/drivers/scsi/qla2xxx/qla_target.h > @@ -813,7 +813,6 @@ struct qla_tgt_sess { > unsigned int conf_compl_supported:1; > unsigned int deleted:1; > unsigned int local:1; > - unsigned int tearing_down:1; > > struct se_session *se_sess; > struct scsi_qla_host *vha; > diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c > index 6e64314..3cb2b97 100644 > --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c > +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c > @@ -466,7 +466,6 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_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); > ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 2/7] target: Un-export target_get_sess_cmd() 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier 2012-07-16 18:04 ` [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 22:54 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 3/7] sbp-target: Consolidate duplicated error path code in sbp_handle_command() Roland Dreier ` (4 subsequent siblings) 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi From: Roland Dreier <roland@purestorage.com> There are no in-tree users of target_get_sess_cmd() outside of target_core_transport.c. Any new code should use the higher-level target_submit_cmd() interface. So let's un-export target_get_sess_cmd() and make it static to the one file where it's actually used. Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/target/target_core_transport.c | 6 +++--- include/target/target_core_fabric.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 634d0f3..82e40e1 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -73,6 +73,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); +static void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); static void transport_put_cmd(struct se_cmd *cmd); static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); @@ -3648,8 +3649,8 @@ EXPORT_SYMBOL(transport_generic_free_cmd); * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; @@ -3669,7 +3670,6 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, se_cmd->check_release = 1; spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } -EXPORT_SYMBOL(target_get_sess_cmd); static void target_release_cmd_kref(struct kref *kref) { diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index c78a233..1e68882 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -129,7 +129,6 @@ bool transport_wait_for_tasks(struct se_cmd *); int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); -void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); int target_put_sess_cmd(struct se_session *, struct se_cmd *); void target_splice_sess_cmd_list(struct se_session *); void target_wait_for_sess_cmds(struct se_session *, int); -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 2/7] target: Un-export target_get_sess_cmd() 2012-07-16 18:04 ` [PATCH 2/7] target: Un-export target_get_sess_cmd() Roland Dreier @ 2012-07-16 22:54 ` Nicholas A. Bellinger 0 siblings, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 22:54 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > There are no in-tree users of target_get_sess_cmd() outside of > target_core_transport.c. Any new code should use the higher-level > target_submit_cmd() interface. So let's un-export target_get_sess_cmd() > and make it static to the one file where it's actually used. > > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/target/target_core_transport.c | 6 +++--- > include/target/target_core_fabric.h | 1 - > 2 files changed, 3 insertions(+), 4 deletions(-) > Applied with some minor fuzz against for-next. Thanks! ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 3/7] sbp-target: Consolidate duplicated error path code in sbp_handle_command() 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier 2012-07-16 18:04 ` [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down Roland Dreier 2012-07-16 18:04 ` [PATCH 2/7] target: Un-export target_get_sess_cmd() Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 22:55 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 4/7] target: Allow for target_submit_cmd() returning errors Roland Dreier ` (3 subsequent siblings) 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger Cc: target-devel, linux-scsi, Chris Boot, Stefan Richter From: Roland Dreier <roland@purestorage.com> Cc: Chris Boot <bootc@bootc.net> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/target/sbp/sbp_target.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 7e6136e..2425ca4 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1219,28 +1219,14 @@ static void sbp_handle_command(struct sbp_target_request *req) ret = sbp_fetch_command(req); if (ret) { pr_debug("sbp_handle_command: fetch command failed: %d\n", ret); - req->status.status |= cpu_to_be32( - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | - STATUS_BLOCK_DEAD(0) | - STATUS_BLOCK_LEN(1) | - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); - sbp_send_status(req); - sbp_free_request(req); - return; + goto err; } ret = sbp_fetch_page_table(req); if (ret) { pr_debug("sbp_handle_command: fetch page table failed: %d\n", ret); - req->status.status |= cpu_to_be32( - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | - STATUS_BLOCK_DEAD(0) | - STATUS_BLOCK_LEN(1) | - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); - sbp_send_status(req); - sbp_free_request(req); - return; + goto err; } unpacked_lun = req->login->lun->unpacked_lun; @@ -1252,6 +1238,16 @@ static void sbp_handle_command(struct sbp_target_request *req) target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, req->sense_buf, unpacked_lun, data_length, MSG_SIMPLE_TAG, data_dir, 0); + return; + +err: + req->status.status |= cpu_to_be32( + STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | + STATUS_BLOCK_DEAD(0) | + STATUS_BLOCK_LEN(1) | + STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); + sbp_send_status(req); + sbp_free_request(req); } /* -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 3/7] sbp-target: Consolidate duplicated error path code in sbp_handle_command() 2012-07-16 18:04 ` [PATCH 3/7] sbp-target: Consolidate duplicated error path code in sbp_handle_command() Roland Dreier @ 2012-07-16 22:55 ` Nicholas A. Bellinger 0 siblings, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 22:55 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi, Chris Boot, Stefan Richter On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > Cc: Chris Boot <bootc@bootc.net> > Cc: Stefan Richter <stefanr@s5r6.in-berlin.de> > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/target/sbp/sbp_target.c | 28 ++++++++++++---------------- > 1 file changed, 12 insertions(+), 16 deletions(-) > Looks like a reasonable 'de-dupe'. Applied to for-next. > diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c > index 7e6136e..2425ca4 100644 > --- a/drivers/target/sbp/sbp_target.c > +++ b/drivers/target/sbp/sbp_target.c > @@ -1219,28 +1219,14 @@ static void sbp_handle_command(struct sbp_target_request *req) > ret = sbp_fetch_command(req); > if (ret) { > pr_debug("sbp_handle_command: fetch command failed: %d\n", ret); > - req->status.status |= cpu_to_be32( > - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | > - STATUS_BLOCK_DEAD(0) | > - STATUS_BLOCK_LEN(1) | > - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); > - sbp_send_status(req); > - sbp_free_request(req); > - return; > + goto err; > } > > ret = sbp_fetch_page_table(req); > if (ret) { > pr_debug("sbp_handle_command: fetch page table failed: %d\n", > ret); > - req->status.status |= cpu_to_be32( > - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | > - STATUS_BLOCK_DEAD(0) | > - STATUS_BLOCK_LEN(1) | > - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); > - sbp_send_status(req); > - sbp_free_request(req); > - return; > + goto err; > } > > unpacked_lun = req->login->lun->unpacked_lun; > @@ -1252,6 +1238,16 @@ static void sbp_handle_command(struct sbp_target_request *req) > target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, > req->sense_buf, unpacked_lun, data_length, > MSG_SIMPLE_TAG, data_dir, 0); > + return; > + > +err: > + req->status.status |= cpu_to_be32( > + STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | > + STATUS_BLOCK_DEAD(0) | > + STATUS_BLOCK_LEN(1) | > + STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); > + sbp_send_status(req); > + sbp_free_request(req); > } > > /* ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 4/7] target: Allow for target_submit_cmd() returning errors 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier ` (2 preceding siblings ...) 2012-07-16 18:04 ` [PATCH 3/7] sbp-target: Consolidate duplicated error path code in sbp_handle_command() Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 23:00 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() Roland Dreier ` (2 subsequent siblings) 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi, Chris Boot, Stefan Richter, Mark Rustad, Signed-off-by: Sebastian Andrzej Siewior, Felipe Balbi From: Roland Dreier <roland@purestorage.com> We want it to be possible for target_submit_cmd() to return errors up to its fabric module callers. For now just update the prototype to return an int, and update all callers to handle non-zero return values as an error. Cc: Chad Dupuis <chad.dupuis@qlogic.com> Cc: Arun Easi <arun.easi@qlogic.com> Cc: Chris Boot <bootc@bootc.net> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de> Cc: Mark Rustad <mark.d.rustad@intel.com> Cc: Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Felipe Balbi <balbi@ti.com> Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 7 +++---- drivers/target/sbp/sbp_target.c | 8 +++++--- drivers/target/target_core_transport.c | 9 +++++---- drivers/target/tcm_fc/tfc_cmd.c | 8 +++++--- drivers/usb/gadget/tcm_usb_gadget.c | 20 ++++++++------------ include/target/target_core_fabric.h | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 3cb2b97..7db7ca7 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -599,10 +599,9 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, return -EINVAL; } - target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], - cmd->unpacked_lun, data_length, fcp_task_attr, - data_dir, flags); - return 0; + return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], + cmd->unpacked_lun, data_length, fcp_task_attr, + data_dir, flags); } static void tcm_qla2xxx_do_rsp(struct work_struct *work) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 2425ca4..fb75d05 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1235,9 +1235,11 @@ static void sbp_handle_command(struct sbp_target_request *req) pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", req->orb_pointer, unpacked_lun, data_length, data_dir); - target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, - req->sense_buf, unpacked_lun, data_length, - MSG_SIMPLE_TAG, data_dir, 0); + if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, + req->sense_buf, unpacked_lun, data_length, + MSG_SIMPLE_TAG, data_dir, 0)) + goto err; + return; err: diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 82e40e1..34ca821 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1544,7 +1544,7 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); * This may only be called from process context, and also currently * assumes internal allocation of fabric payload buffer by target-core. **/ -void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, +int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags) { @@ -1583,7 +1583,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); target_put_sess_cmd(se_sess, se_cmd); - return; + return 0; } /* * Sanitize CDBs via transport_generic_cmd_sequencer() and @@ -1592,7 +1592,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { transport_generic_request_failure(se_cmd); - return; + return 0; } /* @@ -1608,7 +1608,8 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, * when fabric has filled the incoming buffer. */ transport_handle_cdb_direct(se_cmd); - return; + + return 0; } EXPORT_SYMBOL(target_submit_cmd); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index f03fb97..c7c90aa 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -541,9 +541,11 @@ static void ft_send_work(struct work_struct *work) * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path. */ - target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, - &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), - ntohl(fcp->fc_dl), task_attr, data_dir, 0); + if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + ntohl(fcp->fc_dl), task_attr, data_dir, 0)) + goto err; + pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); return; diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index c46439c..53aafd2 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1060,7 +1060,10 @@ static void usbg_cmd_work(struct work_struct *work) tpg = cmd->fu->tpg; tv_nexus = tpg->tpg_nexus; dir = get_cmd_dir(cmd->cmd_buf); - if (dir < 0) { + if (dir < 0 || + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE)) { transport_init_se_cmd(se_cmd, tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, @@ -1069,12 +1072,7 @@ static void usbg_cmd_work(struct work_struct *work) transport_send_check_condition_and_sense(se_cmd, TCM_UNSUPPORTED_SCSI_OPCODE, 1); usbg_cleanup_cmd(cmd); - return; } - - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, - cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); } static int usbg_submit_command(struct f_uas *fu, @@ -1172,7 +1170,10 @@ static void bot_cmd_work(struct work_struct *work) tpg = cmd->fu->tpg; tv_nexus = tpg->tpg_nexus; dir = get_cmd_dir(cmd->cmd_buf); - if (dir < 0) { + if (dir < 0 || + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, + cmd->data_len, cmd->prio_attr, dir, 0)) { transport_init_se_cmd(se_cmd, tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, @@ -1181,12 +1182,7 @@ static void bot_cmd_work(struct work_struct *work) transport_send_check_condition_and_sense(se_cmd, TCM_UNSUPPORTED_SCSI_OPCODE, 1); usbg_cleanup_cmd(cmd); - return; } - - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, - cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - cmd->data_len, cmd->prio_attr, dir, 0); } static int bot_submit_command(struct f_uas *fu, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 1e68882..4f8e515 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -108,7 +108,7 @@ void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); int transport_lookup_cmd_lun(struct se_cmd *, u32); int target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); -void target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, +int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, unsigned char *, u32, u32, int, int, int); int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *sense, u32 unpacked_lun, -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 4/7] target: Allow for target_submit_cmd() returning errors 2012-07-16 18:04 ` [PATCH 4/7] target: Allow for target_submit_cmd() returning errors Roland Dreier @ 2012-07-16 23:00 ` Nicholas A. Bellinger 2012-07-16 23:05 ` Roland Dreier 0 siblings, 1 reply; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 23:00 UTC (permalink / raw) To: Roland Dreier Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi, Chris Boot, Stefan Richter, Mark Rustad, Signed-off-by: Sebastian Andrzej Siewior, Felipe Balbi, Andy Grover On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > We want it to be possible for target_submit_cmd() to return errors up > to its fabric module callers. For now just update the prototype to > return an int, and update all callers to handle non-zero return values > as an error. > Mmmm. The original target_submit_cmd() code had been propagating up a return value, but then we decided (via Agrover's patch) that it made more sense for target_submit_cmd() to always handle exceptions via normal TFO callbacks, and not have the fabric worry about the return here.. Also, I'm not sure if the error paths that this patch now accesses after target_submit_cmd() failure are going to deal with different types of target_submit_cmd() failures correctly. So NACK for the moment, as I don't really see why this is necessary in the first place..? > Cc: Chad Dupuis <chad.dupuis@qlogic.com> > Cc: Arun Easi <arun.easi@qlogic.com> > Cc: Chris Boot <bootc@bootc.net> > Cc: Stefan Richter <stefanr@s5r6.in-berlin.de> > Cc: Mark Rustad <mark.d.rustad@intel.com> > Cc: Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> > Cc: Felipe Balbi <balbi@ti.com> > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/scsi/qla2xxx/tcm_qla2xxx.c | 7 +++---- > drivers/target/sbp/sbp_target.c | 8 +++++--- > drivers/target/target_core_transport.c | 9 +++++---- > drivers/target/tcm_fc/tfc_cmd.c | 8 +++++--- > drivers/usb/gadget/tcm_usb_gadget.c | 20 ++++++++------------ > include/target/target_core_fabric.h | 2 +- > 6 files changed, 27 insertions(+), 27 deletions(-) > > diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c > index 3cb2b97..7db7ca7 100644 > --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c > +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c > @@ -599,10 +599,9 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, > return -EINVAL; > } > > - target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], > - cmd->unpacked_lun, data_length, fcp_task_attr, > - data_dir, flags); > - return 0; > + return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], > + cmd->unpacked_lun, data_length, fcp_task_attr, > + data_dir, flags); > } > > static void tcm_qla2xxx_do_rsp(struct work_struct *work) > diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c > index 2425ca4..fb75d05 100644 > --- a/drivers/target/sbp/sbp_target.c > +++ b/drivers/target/sbp/sbp_target.c > @@ -1235,9 +1235,11 @@ static void sbp_handle_command(struct sbp_target_request *req) > pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", > req->orb_pointer, unpacked_lun, data_length, data_dir); > > - target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, > - req->sense_buf, unpacked_lun, data_length, > - MSG_SIMPLE_TAG, data_dir, 0); > + if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, > + req->sense_buf, unpacked_lun, data_length, > + MSG_SIMPLE_TAG, data_dir, 0)) > + goto err; > + > return; > > err: > diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c > index 82e40e1..34ca821 100644 > --- a/drivers/target/target_core_transport.c > +++ b/drivers/target/target_core_transport.c > @@ -1544,7 +1544,7 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); > * This may only be called from process context, and also currently > * assumes internal allocation of fabric payload buffer by target-core. > **/ > -void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, > +int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, > unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, > u32 data_length, int task_attr, int data_dir, int flags) > { > @@ -1583,7 +1583,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, > transport_send_check_condition_and_sense(se_cmd, > se_cmd->scsi_sense_reason, 0); > target_put_sess_cmd(se_sess, se_cmd); > - return; > + return 0; > } > /* > * Sanitize CDBs via transport_generic_cmd_sequencer() and > @@ -1592,7 +1592,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, > rc = target_setup_cmd_from_cdb(se_cmd, cdb); > if (rc != 0) { > transport_generic_request_failure(se_cmd); > - return; > + return 0; > } > > /* > @@ -1608,7 +1608,8 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, > * when fabric has filled the incoming buffer. > */ > transport_handle_cdb_direct(se_cmd); > - return; > + > + return 0; > } > EXPORT_SYMBOL(target_submit_cmd); > > diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c > index f03fb97..c7c90aa 100644 > --- a/drivers/target/tcm_fc/tfc_cmd.c > +++ b/drivers/target/tcm_fc/tfc_cmd.c > @@ -541,9 +541,11 @@ static void ft_send_work(struct work_struct *work) > * Use a single se_cmd->cmd_kref as we expect to release se_cmd > * directly from ft_check_stop_free callback in response path. > */ > - target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, > - &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), > - ntohl(fcp->fc_dl), task_attr, data_dir, 0); > + if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, > + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), > + ntohl(fcp->fc_dl), task_attr, data_dir, 0)) > + goto err; > + > pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); > return; > > diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c > index c46439c..53aafd2 100644 > --- a/drivers/usb/gadget/tcm_usb_gadget.c > +++ b/drivers/usb/gadget/tcm_usb_gadget.c > @@ -1060,7 +1060,10 @@ static void usbg_cmd_work(struct work_struct *work) > tpg = cmd->fu->tpg; > tv_nexus = tpg->tpg_nexus; > dir = get_cmd_dir(cmd->cmd_buf); > - if (dir < 0) { > + if (dir < 0 || > + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, > + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, > + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE)) { > transport_init_se_cmd(se_cmd, > tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, > tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, > @@ -1069,12 +1072,7 @@ static void usbg_cmd_work(struct work_struct *work) > transport_send_check_condition_and_sense(se_cmd, > TCM_UNSUPPORTED_SCSI_OPCODE, 1); > usbg_cleanup_cmd(cmd); > - return; > } > - > - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, > - cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, > - 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); > } > > static int usbg_submit_command(struct f_uas *fu, > @@ -1172,7 +1170,10 @@ static void bot_cmd_work(struct work_struct *work) > tpg = cmd->fu->tpg; > tv_nexus = tpg->tpg_nexus; > dir = get_cmd_dir(cmd->cmd_buf); > - if (dir < 0) { > + if (dir < 0 || > + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, > + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, > + cmd->data_len, cmd->prio_attr, dir, 0)) { > transport_init_se_cmd(se_cmd, > tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, > tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, > @@ -1181,12 +1182,7 @@ static void bot_cmd_work(struct work_struct *work) > transport_send_check_condition_and_sense(se_cmd, > TCM_UNSUPPORTED_SCSI_OPCODE, 1); > usbg_cleanup_cmd(cmd); > - return; > } > - > - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, > - cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, > - cmd->data_len, cmd->prio_attr, dir, 0); > } > > static int bot_submit_command(struct f_uas *fu, > diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h > index 1e68882..4f8e515 100644 > --- a/include/target/target_core_fabric.h > +++ b/include/target/target_core_fabric.h > @@ -108,7 +108,7 @@ void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, > struct se_session *, u32, int, int, unsigned char *); > int transport_lookup_cmd_lun(struct se_cmd *, u32); > int target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); > -void target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, > +int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, > unsigned char *, u32, u32, int, int, int); > int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, > unsigned char *sense, u32 unpacked_lun, ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 4/7] target: Allow for target_submit_cmd() returning errors 2012-07-16 23:00 ` Nicholas A. Bellinger @ 2012-07-16 23:05 ` Roland Dreier 2012-07-16 23:37 ` Nicholas A. Bellinger 0 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 23:05 UTC (permalink / raw) To: Nicholas A. Bellinger Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi, Chris Boot, Stefan Richter, Mark Rustad, Signed-off-by: Sebastian Andrzej Siewior, Felipe Balbi, Andy Grover On Mon, Jul 16, 2012 at 4:00 PM, Nicholas A. Bellinger <nab@linux-iscsi.org> wrote: > Mmmm. The original target_submit_cmd() code had been propagating up a > return value, but then we decided (via Agrover's patch) that it made > more sense for target_submit_cmd() to always handle exceptions via > normal TFO callbacks, and not have the fabric worry about the return > here.. > > Also, I'm not sure if the error paths that this patch now accesses after > target_submit_cmd() failure are going to deal with different types of > target_submit_cmd() failures correctly. > > So NACK for the moment, as I don't really see why this is necessary in > the first place..? Read on in the series to see why this is needed; in short, for qla2xxx at least, we need a race-free way to check for sess_tearing_down atomically with actually adding the command to sess_cmd_list. I'm OK with returning failure via callback, but a) I'm not sure we can use the normal TFO callbacks in case we can't add the command to sess_cmd_list (seems like it opens the door to other use-after-frees in qla2xxx at least) b) Maybe it's OK if we say that failure to add the command to the sess_cmd_list is the only time submit cmd fails? The qla2xxx race/use-after-free is definitely real, we hit it in testing here with active IO across ACL changes. - R. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 4/7] target: Allow for target_submit_cmd() returning errors 2012-07-16 23:05 ` Roland Dreier @ 2012-07-16 23:37 ` Nicholas A. Bellinger 0 siblings, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 23:37 UTC (permalink / raw) To: Roland Dreier Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi, Chris Boot, Stefan Richter, Mark Rustad, Signed-off-by: Sebastian Andrzej Siewior, Felipe Balbi, Andy Grover On Mon, 2012-07-16 at 16:05 -0700, Roland Dreier wrote: > On Mon, Jul 16, 2012 at 4:00 PM, Nicholas A. Bellinger > <nab@linux-iscsi.org> wrote: > > Mmmm. The original target_submit_cmd() code had been propagating up a > > return value, but then we decided (via Agrover's patch) that it made > > more sense for target_submit_cmd() to always handle exceptions via > > normal TFO callbacks, and not have the fabric worry about the return > > here.. > > > > Also, I'm not sure if the error paths that this patch now accesses after > > target_submit_cmd() failure are going to deal with different types of > > target_submit_cmd() failures correctly. > > > > So NACK for the moment, as I don't really see why this is necessary in > > the first place..? > > Read on in the series to see why this is needed; in short, for qla2xxx > at least, we need a race-free way to check for sess_tearing_down > atomically with actually adding the command to sess_cmd_list. > <nod> > I'm OK with returning failure via callback, but > > a) I'm not sure we can use the normal TFO callbacks in case > we can't add the command to sess_cmd_list (seems like it > opens the door to other use-after-frees in qla2xxx at least) The TFO callback to release qla_tgt_cmd memory would be the same here, so it would be a internal release for target_get_sess_cmd() failures that is careful with items have not been setup in the passed fabric_tgt_cmd->se_cmd due to the session shutdown exception. As commands are received during session shutdown, dispatching their handling to tcm_qla2xxx_free_wq to do extra HW descriptor cleanup would be nice if we can get away without actually sending a proper SCSI response during session shutdown.. > b) Maybe it's OK if we say that failure to add the command to > the sess_cmd_list is the only time submit cmd fails? > I'd still like to avoid (re)propagating up a return value of target_submit_cmd() if at all possible.. > The qla2xxx race/use-after-free is definitely real, we hit it in testing > here with active IO across ACL changes. > > - R. > -- > To unsubscribe from this list: send the line "unsubscribe target-devel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier ` (3 preceding siblings ...) 2012-07-16 18:04 ` [PATCH 4/7] target: Allow for target_submit_cmd() returning errors Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 23:08 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 6/7] qla2xxx: Remove racy, now-redundant check of sess_tearing_down Roland Dreier 2012-07-16 18:04 ` [PATCH 7/7] target: Remove se_session.sess_wait_list Roland Dreier 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi From: Roland Dreier <roland@purestorage.com> Target core code assumes that target_splice_sess_cmd_list() has set sess_tearing_down and moved the list of pending commands to sess_wait_list, no more commands will be added to the session; if any are added, nothing keeps the se_session from being freed while the command is still in flight, which e.g. leads to use-after-free of se_cmd->se_sess in target_release_cmd_kref(). To enforce this invariant, put a check of sess_tearing_down inside of sess_cmd_lock in target_get_sess_cmd(); any checks before this are racy and can lead to the use-after-free described above. For example, the qla_target check in qlt_do_work() checks sess_tearing_down from work thread context but then drops all locks before calling target_submit_cmd() (as it must, since that is a sleeping function). However, since no locks are held, anything can happen with respect to the session it has looked up -- although it does correctly get sess_kref within its lock, so the memory won't be freed while target_submit_cmd() is actually running, nothing stops eg an ACL from being dropped and calling ->shutdown_session() (which calls into target_splice_sess_cmd_list()) before we get to target_get_sess_cmd(). Once this happens, the se_session memory can be freed as soon as target_submit_cmd() returns and qlt_do_work() drops its reference, even though we've just added a command to sess_cmd_list. To prevent this use-after-free, check sess_tearing_down inside of sess_cmd_lock right before target_get_sess_cmd() adds a command to sess_cmd_list; this is synchronized with target_splice_sess_cmd_list() so that every command is either waited for or not added to the queue. Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/target/target_core_transport.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 34ca821..23e6e2d 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -73,7 +73,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); -static void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); +static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); static void transport_put_cmd(struct se_cmd *cmd); static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); @@ -1570,7 +1570,9 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, * for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (rc) + return rc; /* * Signal bidirectional data payloads to target-core */ @@ -1664,7 +1666,11 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, se_cmd->se_tmr_req->ref_task_tag = tag; /* See target_submit_cmd for commentary */ - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (ret) { + core_tmr_release_req(se_cmd->se_tmr_req); + return ret; + } ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); if (ret) { @@ -3650,10 +3656,11 @@ EXPORT_SYMBOL(transport_generic_free_cmd); * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; + int ret = 0; kref_init(&se_cmd->cmd_kref); /* @@ -3667,9 +3674,16 @@ static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cm } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + if (se_sess->sess_tearing_down) { + ret = -ESHUTDOWN; + goto out; + } list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); se_cmd->check_release = 1; + +out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + return ret; } static void target_release_cmd_kref(struct kref *kref) -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-16 18:04 ` [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() Roland Dreier @ 2012-07-16 23:08 ` Nicholas A. Bellinger 2012-07-16 23:21 ` Roland Dreier 0 siblings, 1 reply; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 23:08 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi, Andy Grover On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > Target core code assumes that target_splice_sess_cmd_list() has set > sess_tearing_down and moved the list of pending commands to > sess_wait_list, no more commands will be added to the session; if any > are added, nothing keeps the se_session from being freed while the > command is still in flight, which e.g. leads to use-after-free of > se_cmd->se_sess in target_release_cmd_kref(). > > To enforce this invariant, put a check of sess_tearing_down inside of > sess_cmd_lock in target_get_sess_cmd(); any checks before this are > racy and can lead to the use-after-free described above. For example, > the qla_target check in qlt_do_work() checks sess_tearing_down from > work thread context but then drops all locks before calling > target_submit_cmd() (as it must, since that is a sleeping function). > > However, since no locks are held, anything can happen with respect to > the session it has looked up -- although it does correctly get > sess_kref within its lock, so the memory won't be freed while > target_submit_cmd() is actually running, nothing stops eg an ACL from > being dropped and calling ->shutdown_session() (which calls into > target_splice_sess_cmd_list()) before we get to target_get_sess_cmd(). > Once this happens, the se_session memory can be freed as soon as > target_submit_cmd() returns and qlt_do_work() drops its reference, > even though we've just added a command to sess_cmd_list. > > To prevent this use-after-free, check sess_tearing_down inside of > sess_cmd_lock right before target_get_sess_cmd() adds a command to > sess_cmd_list; this is synchronized with target_splice_sess_cmd_list() > so that every command is either waited for or not added to the queue. > > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/target/target_core_transport.c | 24 +++++++++++++++++++----- > 1 file changed, 19 insertions(+), 5 deletions(-) > > diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c > index 34ca821..23e6e2d 100644 > --- a/drivers/target/target_core_transport.c > +++ b/drivers/target/target_core_transport.c > @@ -73,7 +73,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd); > static void transport_handle_queue_full(struct se_cmd *cmd, > struct se_device *dev); > static int transport_generic_get_mem(struct se_cmd *cmd); > -static void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); > +static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); > static void transport_put_cmd(struct se_cmd *cmd); > static void transport_remove_cmd_from_queue(struct se_cmd *cmd); > static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); > @@ -1570,7 +1570,9 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, > * for fabrics using TARGET_SCF_ACK_KREF that expect a second > * kref_put() to happen during fabric packet acknowledgement. > */ > - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); > + rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); > + if (rc) > + return rc; OK, I see where you where going with the target_submit_cmd() failure here now.. However, I'm still leaning towards a way to do this for tcm_qla2xxx that does not require all fabric callers to handle target_submit_cmd() exceptions directly.. How about a special target_get_sess_cmd() failure callback to free se_cmd when target_get_sess_cmd() fails, but not actually send a SCSI response back out to the fabric here during session shutdown..? That said, I'm going to commit this patch (slightly changed to keep target_submit_cmd() returning void for now) but I'd still like a better way of handling this particular failure without propagating up the return value. > /* > * Signal bidirectional data payloads to target-core > */ > @@ -1664,7 +1666,11 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, > se_cmd->se_tmr_req->ref_task_tag = tag; > > /* See target_submit_cmd for commentary */ > - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); > + ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); > + if (ret) { > + core_tmr_release_req(se_cmd->se_tmr_req); > + return ret; > + } > > ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); > if (ret) { > @@ -3650,10 +3656,11 @@ EXPORT_SYMBOL(transport_generic_free_cmd); > * @se_cmd: command descriptor to add > * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() > */ > -static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, > - bool ack_kref) > +static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, > + bool ack_kref) > { > unsigned long flags; > + int ret = 0; > > kref_init(&se_cmd->cmd_kref); > /* > @@ -3667,9 +3674,16 @@ static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cm > } > > spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); > + if (se_sess->sess_tearing_down) { > + ret = -ESHUTDOWN; > + goto out; > + } > list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); > se_cmd->check_release = 1; > + > +out: > spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); > + return ret; > } > > static void target_release_cmd_kref(struct kref *kref) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-16 23:08 ` Nicholas A. Bellinger @ 2012-07-16 23:21 ` Roland Dreier 2012-07-17 1:40 ` Roland Dreier 0 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 23:21 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi, Andy Grover On Mon, Jul 16, 2012 at 4:08 PM, Nicholas A. Bellinger <nab@linux-iscsi.org> wrote: > However, I'm still leaning towards a way to do this for tcm_qla2xxx that > does not require all fabric callers to handle target_submit_cmd() > exceptions directly.. > > How about a special target_get_sess_cmd() failure callback to free > se_cmd when target_get_sess_cmd() fails, but not actually send a SCSI > response back out to the fabric here during session shutdown..? I guess that's OK, although I'm not sure it ends up being cleaner. If you look at my 4/7 patch, you see that all target_submit_cmd callers have an error path where they handle terminating commands that fail processing just before calling submit_cmd anyway. eg for qla2xxx we'll need a callback to call qlt_send_term_exchange() in addition to the error path call that qlt_do_work() has anyway. Similarly tcm_fc ends up with a second call to ft_send_resp_code_and_free(). etc. But I don't really have a strong feeling about this, if the view is that submit_cmd() should never return failure directly then I'm OK with that. > That said, I'm going to commit this patch (slightly changed to keep > target_submit_cmd() returning void for now) but I'd still like a better > way of handling this particular failure without propagating up the > return value. OK, I'll take a look at how you handle this... - R. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-16 23:21 ` Roland Dreier @ 2012-07-17 1:40 ` Roland Dreier 2012-07-17 1:56 ` Nicholas A. Bellinger 0 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-17 1:40 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi, Andy Grover > OK, I'll take a look at how you handle this... So looking at commit bc187ea6c3b3 in the tree you just pushed out ("target: Check sess_tearing_down in target_get_sess_cmd()") it looks like you just return from target_submit_cmd() if we fail to add the command to sess_cmd_list -- doesn't this mean we just leak those commands and possibly leave the HW sitting there with open exchanges? Do you have a plan for how to handle this? Do we really want to plumb through another callback to tell the fabric driver to free the command in this case? - R. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-17 1:40 ` Roland Dreier @ 2012-07-17 1:56 ` Nicholas A. Bellinger 2012-07-17 1:59 ` Nicholas A. Bellinger 2012-07-17 16:34 ` Roland Dreier 0 siblings, 2 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-17 1:56 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi, Andy Grover On Mon, 2012-07-16 at 18:40 -0700, Roland Dreier wrote: > > OK, I'll take a look at how you handle this... > > So looking at commit bc187ea6c3b3 in the tree you just pushed out > ("target: Check sess_tearing_down in target_get_sess_cmd()") it looks > like you just return from target_submit_cmd() if we fail to add the > command to sess_cmd_list -- doesn't this mean we just leak those > commands and possibly leave the HW sitting there with open exchanges? > With dropping patch #5 for now, I assume that would be the case.. > Do you have a plan for how to handle this? Do we really want to plumb > through another callback to tell the fabric driver to free the command > in this case? > I need to think more about this ahead of changing it back again for-3.6 now that other fabrics have the assumption of target_submit_cmd() would not fail. There is a clear case with qla2xxx for just changing it back (we might end up doing that just yet) but I wanted to get the other important bits into for-next into place first.. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-17 1:56 ` Nicholas A. Bellinger @ 2012-07-17 1:59 ` Nicholas A. Bellinger 2012-07-17 16:34 ` Roland Dreier 1 sibling, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-17 1:59 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi, Andy Grover On Mon, 2012-07-16 at 18:56 -0700, Nicholas A. Bellinger wrote: > On Mon, 2012-07-16 at 18:40 -0700, Roland Dreier wrote: > > > OK, I'll take a look at how you handle this... > > > > So looking at commit bc187ea6c3b3 in the tree you just pushed out > > ("target: Check sess_tearing_down in target_get_sess_cmd()") it looks > > like you just return from target_submit_cmd() if we fail to add the > > command to sess_cmd_list -- doesn't this mean we just leak those > > commands and possibly leave the HW sitting there with open exchanges? > > > > With dropping patch #5 for now, I assume that would be the case.. > Or with patch #4 even.. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-17 1:56 ` Nicholas A. Bellinger 2012-07-17 1:59 ` Nicholas A. Bellinger @ 2012-07-17 16:34 ` Roland Dreier 2012-07-17 16:39 ` Christoph Hellwig 2012-07-17 23:24 ` Nicholas A. Bellinger 1 sibling, 2 replies; 25+ messages in thread From: Roland Dreier @ 2012-07-17 16:34 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi, Andy Grover On Mon, Jul 16, 2012 at 6:56 PM, Nicholas A. Bellinger <nab@linux-iscsi.org> wrote: >> Do you have a plan for how to handle this? Do we really want to plumb >> through another callback to tell the fabric driver to free the command >> in this case? > I need to think more about this ahead of changing it back again for-3.6 > now that other fabrics have the assumption of target_submit_cmd() would > not fail. > There is a clear case with qla2xxx for just changing it back (we might > end up doing that just yet) but I wanted to get the other important bits > into for-next into place first.. Sleeping on things, I now feel pretty strongly that having target_submit_cmd return an error value for "immediate" errors where the command does not make it into the target core is the right approach. Freeing commands is already one of the most confusing and complex parts of the target code, with "check_stop_free," "cmd_wait_comp" and "SCF_ACK_KREF." Adding another code flow back to the fabric driver with yet another set of semantics around freeing a command seems like it's making things even harder to maintain. On the other hand, every caller of target_submit_cmd() in the tree already has an error path where it handles problems it detects right before calling target_submit_cmd(), and so it's trivial to share that for problems detected inside target_submit_cmd(). If you look at patch 4/7, pretty much the only changes are like going from target_submit_cmd(...); to if (target_submit_cmd(...)) goto err; and in fact the ->handle_cmd() wrapper that qla_target uses to call target_submit_cmd via tcm_qla2xxx already has a return value that qla_target handled properly! I guess another approach would be to split target_submit_cmd() into the target_get_sess_cmd() part and the rest of it, and have fabric drivers handle errors queueing commands but not have to worry about the submit cmd part failing. But I'm not sure that's any better. Andy, any feelings about this one way or another? Christoph? Thanks, Roland ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-17 16:34 ` Roland Dreier @ 2012-07-17 16:39 ` Christoph Hellwig 2012-07-17 19:28 ` Andy Grover 2012-07-17 23:24 ` Nicholas A. Bellinger 1 sibling, 1 reply; 25+ messages in thread From: Christoph Hellwig @ 2012-07-17 16:39 UTC (permalink / raw) To: Roland Dreier Cc: Nicholas A. Bellinger, target-devel, linux-scsi, Andy Grover On Tue, Jul 17, 2012 at 09:34:49AM -0700, Roland Dreier wrote: > Sleeping on things, I now feel pretty strongly that having target_submit_cmd > return an error value for "immediate" errors where the command does not > make it into the target core is the right approach. I think it is. When I tried to convert other drivers to target_submit_cmd while doing the target processing thread removal that would have simplified a lot of things. > Freeing commands is already one of the most confusing and complex parts > of the target code, with "check_stop_free," "cmd_wait_comp" and > "SCF_ACK_KREF." Adding another code flow back to the fabric driver > with yet another set of semantics around freeing a command seems like > it's making things even harder to maintain. True. And the above mess really needs to be simplified, too. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-17 16:39 ` Christoph Hellwig @ 2012-07-17 19:28 ` Andy Grover 0 siblings, 0 replies; 25+ messages in thread From: Andy Grover @ 2012-07-17 19:28 UTC (permalink / raw) To: Christoph Hellwig Cc: Roland Dreier, Nicholas A. Bellinger, target-devel, linux-scsi On 07/17/2012 09:39 AM, Christoph Hellwig wrote: > On Tue, Jul 17, 2012 at 09:34:49AM -0700, Roland Dreier wrote: >> Sleeping on things, I now feel pretty strongly that having target_submit_cmd >> return an error value for "immediate" errors where the command does not >> make it into the target core is the right approach. > > I think it is. When I tried to convert other drivers to > target_submit_cmd while doing the target processing thread removal that > would have simplified a lot of things. > >> Freeing commands is already one of the most confusing and complex parts >> of the target code, with "check_stop_free," "cmd_wait_comp" and >> "SCF_ACK_KREF." Adding another code flow back to the fabric driver >> with yet another set of semantics around freeing a command seems like >> it's making things even harder to maintain. > > True. And the above mess really needs to be simplified, too. I'm ok with submit_cmd returning a value for now. Maybe in the end it doesn't, but getting the code working comes first. This is one of those areas that needs a complete rewrite, so who cares if there's some dirt on the floor when the whole joint is due for remodeling. -- Andy ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() 2012-07-17 16:34 ` Roland Dreier 2012-07-17 16:39 ` Christoph Hellwig @ 2012-07-17 23:24 ` Nicholas A. Bellinger 1 sibling, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-17 23:24 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi, Andy Grover On Tue, 2012-07-17 at 09:34 -0700, Roland Dreier wrote: > On Mon, Jul 16, 2012 at 6:56 PM, Nicholas A. Bellinger > <nab@linux-iscsi.org> wrote: > >> Do you have a plan for how to handle this? Do we really want to plumb > >> through another callback to tell the fabric driver to free the command > >> in this case? > > > I need to think more about this ahead of changing it back again for-3.6 > > now that other fabrics have the assumption of target_submit_cmd() would > > not fail. > > > There is a clear case with qla2xxx for just changing it back (we might > > end up doing that just yet) but I wanted to get the other important bits > > into for-next into place first.. > > Sleeping on things, I now feel pretty strongly that having target_submit_cmd > return an error value for "immediate" errors where the command does not > make it into the target core is the right approach. > > Freeing commands is already one of the most confusing and complex parts > of the target code, with "check_stop_free," "cmd_wait_comp" and > "SCF_ACK_KREF." Adding another code flow back to the fabric driver > with yet another set of semantics around freeing a command seems like > it's making things even harder to maintain. > I wasn't talking about adding another release path. I was thinking more about a TFO call to optionally abort HW/SW exchange if we can't accept the command in question. Not to mention, this could end up being useful for other purposes beyond the initial target_submit_cmd() failure case due to active I/O shutdown. (aborts + active I/O shutdown with active SRP WRITEs with ib_srpt come to mind needing something like this..) > On the other hand, every caller of target_submit_cmd() in the tree already > has an error path where it handles problems it detects right before calling > target_submit_cmd(), and so it's trivial to share that for problems detected > inside target_submit_cmd(). If you look at patch 4/7, pretty much the > only changes are like going from > > target_submit_cmd(...); > > to > > if (target_submit_cmd(...)) > goto err; > > and in fact the ->handle_cmd() wrapper that qla_target uses to call > target_submit_cmd via tcm_qla2xxx already has a return value that > qla_target handled properly! > Sure, there is no doubting tcm_qla2xxx's usage of this return value back into qla_target.c code.. > I guess another approach would be to split target_submit_cmd() into > the target_get_sess_cmd() part and the rest of it, and have fabric > drivers handle errors queueing commands but not have to worry about > the submit cmd part failing. But I'm not sure that's any better. > > Andy, any feelings about this one way or another? Christoph? > Ok, so for-3.6 it makes the most sense to just convert this back to propagate up the return code, but only for target_get_sess_cmd() failure case.. That said, I'll go ahead and respin patch #4 on top of for-next, and post the updated patch shortly with the same CC's and ask for ACKs from the necessary folks. --nab ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 6/7] qla2xxx: Remove racy, now-redundant check of sess_tearing_down 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier ` (4 preceding siblings ...) 2012-07-16 18:04 ` [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 23:10 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 7/7] target: Remove se_session.sess_wait_list Roland Dreier 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi From: Roland Dreier <roland@purestorage.com> Now that target_submit_cmd() / target_get_sess_cmd() check sess_tearing_down before adding commands to the list, we no longer need the check in qlt_do_work(). In fact this check is racy anyway (and that race is what inspired the change to add the check of sess_tearing_down to the target core). Cc: Chad Dupuis <chad.dupuis@qlogic.com> Cc: Arun Easi <arun.easi@qlogic.com> Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/scsi/qla2xxx/qla_target.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 87b5a330..5b30132 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2643,19 +2643,9 @@ static void qlt_do_work(struct work_struct *work) spin_lock_irqsave(&ha->hardware_lock, flags); sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); - if (sess) { - if (unlikely(sess->se_sess->sess_tearing_down)) { - sess = NULL; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - goto out_term; - } else { - /* - * Do the extra kref_get() before dropping - * qla_hw_data->hardware_lock. - */ - kref_get(&sess->se_sess->sess_kref); - } - } + /* Do kref_get() before dropping qla_hw_data->hardware_lock. */ + if (sess) + kref_get(&sess->se_sess->sess_kref); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (unlikely(!sess)) { -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 6/7] qla2xxx: Remove racy, now-redundant check of sess_tearing_down 2012-07-16 18:04 ` [PATCH 6/7] qla2xxx: Remove racy, now-redundant check of sess_tearing_down Roland Dreier @ 2012-07-16 23:10 ` Nicholas A. Bellinger 0 siblings, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 23:10 UTC (permalink / raw) To: Roland Dreier Cc: target-devel, linux-scsi, Chad Dupuis, Arun Easi, Christoph Hellwig On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > Now that target_submit_cmd() / target_get_sess_cmd() check > sess_tearing_down before adding commands to the list, we no longer > need the check in qlt_do_work(). In fact this check is racy anyway > (and that race is what inspired the change to add the check of > sess_tearing_down to the target core). > > Cc: Chad Dupuis <chad.dupuis@qlogic.com> > Cc: Arun Easi <arun.easi@qlogic.com> > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/scsi/qla2xxx/qla_target.c | 16 +++------------- > 1 file changed, 3 insertions(+), 13 deletions(-) > Glad to see this one finally go. ;) Applied to for-next > diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c > index 87b5a330..5b30132 100644 > --- a/drivers/scsi/qla2xxx/qla_target.c > +++ b/drivers/scsi/qla2xxx/qla_target.c > @@ -2643,19 +2643,9 @@ static void qlt_do_work(struct work_struct *work) > spin_lock_irqsave(&ha->hardware_lock, flags); > sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, > atio->u.isp24.fcp_hdr.s_id); > - if (sess) { > - if (unlikely(sess->se_sess->sess_tearing_down)) { > - sess = NULL; > - spin_unlock_irqrestore(&ha->hardware_lock, flags); > - goto out_term; > - } else { > - /* > - * Do the extra kref_get() before dropping > - * qla_hw_data->hardware_lock. > - */ > - kref_get(&sess->se_sess->sess_kref); > - } > - } > + /* Do kref_get() before dropping qla_hw_data->hardware_lock. */ > + if (sess) > + kref_get(&sess->se_sess->sess_kref); > spin_unlock_irqrestore(&ha->hardware_lock, flags); > > if (unlikely(!sess)) { ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 7/7] target: Remove se_session.sess_wait_list 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier ` (5 preceding siblings ...) 2012-07-16 18:04 ` [PATCH 6/7] qla2xxx: Remove racy, now-redundant check of sess_tearing_down Roland Dreier @ 2012-07-16 18:04 ` Roland Dreier 2012-07-16 23:15 ` Nicholas A. Bellinger 6 siblings, 1 reply; 25+ messages in thread From: Roland Dreier @ 2012-07-16 18:04 UTC (permalink / raw) To: Nicholas A. Bellinger; +Cc: target-devel, linux-scsi From: Roland Dreier <roland@purestorage.com> Since we set se_session.sess_tearing_down and stop new commands from being added to se_session.sess_cmd_list before we wait for commands to finish when freeing a session, there's no need for a separate sess_wait_list -- if we let new commands be added to sess_cmd_list after setting sess_tearing_down, that would be a bug that breaks the logic of waiting in-flight commands. Also rename target_splice_sess_cmd_list() to target_sess_cmd_list_set_waiting(), since we are no longer splicing onto a separate list. Signed-off-by: Roland Dreier <roland@purestorage.com> --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- drivers/target/target_core_transport.c | 22 ++++++++++------------ include/target/target_core_base.h | 1 - include/target/target_core_fabric.h | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 7db7ca7..72f3557 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -466,7 +466,7 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) vha = sess->vha; spin_lock_irqsave(&vha->hw->hardware_lock, flags); - target_splice_sess_cmd_list(se_sess); + target_sess_cmd_list_set_waiting(se_sess); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); return 1; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 23e6e2d..7b3359e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -244,7 +244,6 @@ struct se_session *transport_init_session(void) INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); INIT_LIST_HEAD(&se_sess->sess_cmd_list); - INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); kref_init(&se_sess->sess_kref); @@ -3719,28 +3718,27 @@ int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) } EXPORT_SYMBOL(target_put_sess_cmd); -/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list - * @se_sess: session to split +/* target_sess_cmd_list_set_waiting - Flag all commands in + * sess_cmd_list to complete cmd_wait_comp. Set + * sess_tearing_down so no more commands are queued. + * @se_sess: session to flag */ -void target_splice_sess_cmd_list(struct se_session *se_sess) +void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { struct se_cmd *se_cmd; unsigned long flags; - WARN_ON(!list_empty(&se_sess->sess_wait_list)); - INIT_LIST_HEAD(&se_sess->sess_wait_list); - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - se_sess->sess_tearing_down = 1; - list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); + WARN_ON(se_sess->sess_tearing_down); + se_sess->sess_tearing_down = 1; - list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) + list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) se_cmd->cmd_wait_set = 1; spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } -EXPORT_SYMBOL(target_splice_sess_cmd_list); +EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); /* target_wait_for_sess_cmds - Wait for outstanding descriptors * @se_sess: session to wait for active I/O @@ -3754,7 +3752,7 @@ void target_wait_for_sess_cmds( bool rc = false; list_for_each_entry_safe(se_cmd, tmp_cmd, - &se_sess->sess_wait_list, se_cmd_list) { + &se_sess->sess_cmd_list, se_cmd_list) { list_del(&se_cmd->se_cmd_list); pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index dc35d86..5d8907e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -633,7 +633,6 @@ struct se_session { struct list_head sess_list; struct list_head sess_acl_list; struct list_head sess_cmd_list; - struct list_head sess_wait_list; spinlock_t sess_cmd_lock; struct kref sess_kref; }; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 4f8e515..86d8a4a 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -130,7 +130,7 @@ int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); int target_put_sess_cmd(struct se_session *, struct se_cmd *); -void target_splice_sess_cmd_list(struct se_session *); +void target_sess_cmd_list_set_waiting(struct se_session *); void target_wait_for_sess_cmds(struct se_session *, int); int core_alua_check_nonop_delay(struct se_cmd *); -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 7/7] target: Remove se_session.sess_wait_list 2012-07-16 18:04 ` [PATCH 7/7] target: Remove se_session.sess_wait_list Roland Dreier @ 2012-07-16 23:15 ` Nicholas A. Bellinger 0 siblings, 0 replies; 25+ messages in thread From: Nicholas A. Bellinger @ 2012-07-16 23:15 UTC (permalink / raw) To: Roland Dreier; +Cc: target-devel, linux-scsi On Mon, 2012-07-16 at 11:04 -0700, Roland Dreier wrote: > From: Roland Dreier <roland@purestorage.com> > > Since we set se_session.sess_tearing_down and stop new commands from > being added to se_session.sess_cmd_list before we wait for commands to > finish when freeing a session, there's no need for a separate > sess_wait_list -- if we let new commands be added to sess_cmd_list > after setting sess_tearing_down, that would be a bug that breaks the > logic of waiting in-flight commands. > > Also rename target_splice_sess_cmd_list() to > target_sess_cmd_list_set_waiting(), since we are no longer splicing > onto a separate list. > So it looks reasonable to drop this cruft now, aside from the target_get_sess_cmd() failure bit that still needs to be worked out for-3.6 code. Nice work Roland & Pure folks! > > > Signed-off-by: Roland Dreier <roland@purestorage.com> > --- > drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- > drivers/target/target_core_transport.c | 22 ++++++++++------------ > include/target/target_core_base.h | 1 - > include/target/target_core_fabric.h | 2 +- > 4 files changed, 12 insertions(+), 15 deletions(-) > > diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c > index 7db7ca7..72f3557 100644 > --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c > +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c > @@ -466,7 +466,7 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) > vha = sess->vha; > > spin_lock_irqsave(&vha->hw->hardware_lock, flags); > - target_splice_sess_cmd_list(se_sess); > + target_sess_cmd_list_set_waiting(se_sess); > spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); > > return 1; > diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c > index 23e6e2d..7b3359e 100644 > --- a/drivers/target/target_core_transport.c > +++ b/drivers/target/target_core_transport.c > @@ -244,7 +244,6 @@ struct se_session *transport_init_session(void) > INIT_LIST_HEAD(&se_sess->sess_list); > INIT_LIST_HEAD(&se_sess->sess_acl_list); > INIT_LIST_HEAD(&se_sess->sess_cmd_list); > - INIT_LIST_HEAD(&se_sess->sess_wait_list); > spin_lock_init(&se_sess->sess_cmd_lock); > kref_init(&se_sess->sess_kref); > > @@ -3719,28 +3718,27 @@ int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) > } > EXPORT_SYMBOL(target_put_sess_cmd); > > -/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list > - * @se_sess: session to split > +/* target_sess_cmd_list_set_waiting - Flag all commands in > + * sess_cmd_list to complete cmd_wait_comp. Set > + * sess_tearing_down so no more commands are queued. > + * @se_sess: session to flag > */ > -void target_splice_sess_cmd_list(struct se_session *se_sess) > +void target_sess_cmd_list_set_waiting(struct se_session *se_sess) > { > struct se_cmd *se_cmd; > unsigned long flags; > > - WARN_ON(!list_empty(&se_sess->sess_wait_list)); > - INIT_LIST_HEAD(&se_sess->sess_wait_list); > - > spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); > - se_sess->sess_tearing_down = 1; > > - list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); > + WARN_ON(se_sess->sess_tearing_down); > + se_sess->sess_tearing_down = 1; > > - list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) > + list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) > se_cmd->cmd_wait_set = 1; > > spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); > } > -EXPORT_SYMBOL(target_splice_sess_cmd_list); > +EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); > > /* target_wait_for_sess_cmds - Wait for outstanding descriptors > * @se_sess: session to wait for active I/O > @@ -3754,7 +3752,7 @@ void target_wait_for_sess_cmds( > bool rc = false; > > list_for_each_entry_safe(se_cmd, tmp_cmd, > - &se_sess->sess_wait_list, se_cmd_list) { > + &se_sess->sess_cmd_list, se_cmd_list) { > list_del(&se_cmd->se_cmd_list); > > pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" > diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h > index dc35d86..5d8907e 100644 > --- a/include/target/target_core_base.h > +++ b/include/target/target_core_base.h > @@ -633,7 +633,6 @@ struct se_session { > struct list_head sess_list; > struct list_head sess_acl_list; > struct list_head sess_cmd_list; > - struct list_head sess_wait_list; > spinlock_t sess_cmd_lock; > struct kref sess_kref; > }; > diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h > index 4f8e515..86d8a4a 100644 > --- a/include/target/target_core_fabric.h > +++ b/include/target/target_core_fabric.h > @@ -130,7 +130,7 @@ int transport_check_aborted_status(struct se_cmd *, int); > int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); > > int target_put_sess_cmd(struct se_session *, struct se_cmd *); > -void target_splice_sess_cmd_list(struct se_session *); > +void target_sess_cmd_list_set_waiting(struct se_session *); > void target_wait_for_sess_cmds(struct se_session *, int); > > int core_alua_check_nonop_delay(struct se_cmd *); ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2012-07-17 23:24 UTC | newest] Thread overview: 25+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-07-16 18:04 [PATCH 0/7] series to fix qla2xxx use-after-free Roland Dreier 2012-07-16 18:04 ` [PATCH 1/7] qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down Roland Dreier 2012-07-16 22:52 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 2/7] target: Un-export target_get_sess_cmd() Roland Dreier 2012-07-16 22:54 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 3/7] sbp-target: Consolidate duplicated error path code in sbp_handle_command() Roland Dreier 2012-07-16 22:55 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 4/7] target: Allow for target_submit_cmd() returning errors Roland Dreier 2012-07-16 23:00 ` Nicholas A. Bellinger 2012-07-16 23:05 ` Roland Dreier 2012-07-16 23:37 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 5/7] target: Check sess_tearing_down in target_get_sess_cmd() Roland Dreier 2012-07-16 23:08 ` Nicholas A. Bellinger 2012-07-16 23:21 ` Roland Dreier 2012-07-17 1:40 ` Roland Dreier 2012-07-17 1:56 ` Nicholas A. Bellinger 2012-07-17 1:59 ` Nicholas A. Bellinger 2012-07-17 16:34 ` Roland Dreier 2012-07-17 16:39 ` Christoph Hellwig 2012-07-17 19:28 ` Andy Grover 2012-07-17 23:24 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 6/7] qla2xxx: Remove racy, now-redundant check of sess_tearing_down Roland Dreier 2012-07-16 23:10 ` Nicholas A. Bellinger 2012-07-16 18:04 ` [PATCH 7/7] target: Remove se_session.sess_wait_list Roland Dreier 2012-07-16 23:15 ` Nicholas A. Bellinger
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.