Re: [PATCH-v2 1/3] target: Fix LUN_RESET active I/O handling for ACK_KREF

2016-01-28 Thread Sagi Grimberg



+   sess = cmd->se_sess;
+   if (WARN_ON_ONCE(!sess))
+   continue;
+
+   spin_lock(&sess->sess_cmd_lock);
+   rc = __target_check_io_state(cmd);
+   spin_unlock(&sess->sess_cmd_lock);
+   if (!rc) {
+   printk("LUN_RESET I/O: non-zero 
kref_get_unless_zero\n");


Is this message always correct? __target_check_io_state() will return
false for commands that were completed..
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH-v2 1/3] target: Fix LUN_RESET active I/O handling for ACK_KREF

2016-01-27 Thread Nicholas A. Bellinger
On Tue, 2016-01-26 at 18:19 +0100, Christoph Hellwig wrote:
> > +static bool __target_check_io_state(struct se_cmd *se_cmd)
> > +{
> > +   struct se_session *sess = se_cmd->se_sess;
> > +
> > +   assert_spin_locked(&se_session->sess_cmd_lock);
> > +   WARN_ON_ONCE(!irqs_disabled());
> 
> Btw, I looked a the code and can't really see what sess_cmd_lock is
> supposed to protect here.
> 
> > +   sess = cmd->se_sess;
> > +   if (WARN_ON_ONCE(!sess))
> > +   continue;
> > +
> > +   spin_lock(&sess->sess_cmd_lock);
> > +   rc = __target_check_io_state(cmd);
> > +   spin_unlock(&sess->sess_cmd_lock);
> > +   if (!rc) {
> > +   printk("LUN_RESET I/O: non-zero 
> > kref_get_unless_zero\n");
> > +   continue;
> > +   }
> 
> And thus why we care about taking it here.

I'm still working on -v3 series to handle se_session shutdown during
this specific multi-port LUN_RESET case, and considering using the
existing se_cmd->cmd_wait_set bit to signal when this special case
happens.

Currently ->sess_cmd_lock is held in target_release_cmd_kref() and
target_sess_cmd_list_set_waiting() while checking and setting this
value.

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH-v2 1/3] target: Fix LUN_RESET active I/O handling for ACK_KREF

2016-01-26 Thread Christoph Hellwig
> +static bool __target_check_io_state(struct se_cmd *se_cmd)
> +{
> + struct se_session *sess = se_cmd->se_sess;
> +
> + assert_spin_locked(&se_session->sess_cmd_lock);
> + WARN_ON_ONCE(!irqs_disabled());

Btw, I looked a the code and can't really see what sess_cmd_lock is
supposed to protect here.

> + sess = cmd->se_sess;
> + if (WARN_ON_ONCE(!sess))
> + continue;
> +
> + spin_lock(&sess->sess_cmd_lock);
> + rc = __target_check_io_state(cmd);
> + spin_unlock(&sess->sess_cmd_lock);
> + if (!rc) {
> + printk("LUN_RESET I/O: non-zero 
> kref_get_unless_zero\n");
> + continue;
> + }

And thus why we care about taking it here.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH-v2 1/3] target: Fix LUN_RESET active I/O handling for ACK_KREF

2016-01-22 Thread Nicholas A. Bellinger
From: Nicholas Bellinger 

This patch fixes a NULL pointer se_cmd->cmd_kref < 0
refcount bug during TMR LUN_RESET with active se_cmd
I/O, that can be triggered during se_cmd descriptor
shutdown + release via core_tmr_drain_state_list() code.

To address this bug, add common __target_check_io_state()
helper for ABORT_TASK + LUN_RESET w/ CMD_T_COMPLETE
checking, and set CMD_T_ABORTED + obtain ->cmd_kref for
both cases ahead of last target_put_sess_cmd() after
TFO->aborted_task() -> transport_cmd_finish_abort()
callback has completed.

It also introduces SCF_ACK_KREF to determine when
transport_cmd_finish_abort() needs to drop the second
extra reference, ahead of calling target_put_sess_cmd()
for the final kref_put(&se_cmd->cmd_kref).

It also updates transport_cmd_check_stop() to avoid
holding se_cmd->t_state_lock while dropping se_cmd
device state via target_remove_from_state_list(), now
that core_tmr_drain_state_list() is holding the
se_device lock while checking se_cmd state from
within TMR logic.

Finally, move transport_put_cmd() release of SGL +
TMR + extended CDB memory into target_free_cmd_mem()
in order to avoid potential resource leaks in TMR
ABORT_TASK + LUN_RESET code-paths.  Also update
target_release_cmd_kref() accordingly.

Cc: Quinn Tran 
Cc: Himanshu Madhani 
Cc: Sagi Grimberg 
Cc: Christoph Hellwig 
Cc: Hannes Reinecke 
Cc: Andy Grover 
Cc: Mike Christie 
Signed-off-by: Nicholas Bellinger 
---
 drivers/target/target_core_tmr.c   | 66 --
 drivers/target/target_core_transport.c | 56 ++---
 include/target/target_core_base.h  |  1 +
 3 files changed, 75 insertions(+), 48 deletions(-)

diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 7137042..5f315b4 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -107,6 +107,34 @@ static int target_check_cdb_and_preempt(struct list_head 
*list,
return 1;
 }
 
+static bool __target_check_io_state(struct se_cmd *se_cmd)
+{
+   struct se_session *sess = se_cmd->se_sess;
+
+   assert_spin_locked(&se_session->sess_cmd_lock);
+   WARN_ON_ONCE(!irqs_disabled());
+   /*
+* If command already reached CMD_T_COMPLETE state within
+* target_complete_cmd(), this se_cmd has been passed to
+* fabric driver and will not be aborted.
+*
+* Otherwise, obtain a local se_cmd->cmd_kref now for TMR
+* ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
+* long as se_cmd->cmd_kref is still active unless zero.
+*/
+   spin_lock(&se_cmd->t_state_lock);
+   if (se_cmd->transport_state & CMD_T_COMPLETE) {
+   pr_debug("Attempted to abort io tag: %llu already complete,"
+   " skipping\n", se_cmd->tag);
+   spin_unlock(&se_cmd->t_state_lock);
+   return false;
+   }
+   se_cmd->transport_state |= CMD_T_ABORTED;
+   spin_unlock(&se_cmd->t_state_lock);
+
+   return kref_get_unless_zero(&se_cmd->cmd_kref);
+}
+
 void core_tmr_abort_task(
struct se_device *dev,
struct se_tmr_req *tmr,
@@ -133,26 +161,18 @@ void core_tmr_abort_task(
printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
se_cmd->se_tfo->get_fabric_name(), ref_tag);
 
-   spin_lock(&se_cmd->t_state_lock);
-   if (se_cmd->transport_state & CMD_T_COMPLETE) {
-   printk("ABORT_TASK: ref_tag: %llu already complete,"
-  " skipping\n", ref_tag);
-   spin_unlock(&se_cmd->t_state_lock);
+   if (!__target_check_io_state(se_cmd)) {
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
goto out;
}
-   se_cmd->transport_state |= CMD_T_ABORTED;
-   spin_unlock(&se_cmd->t_state_lock);
-
list_del_init(&se_cmd->se_cmd_list);
-   kref_get(&se_cmd->cmd_kref);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
cancel_work_sync(&se_cmd->work);
transport_wait_for_tasks(se_cmd);
 
-   target_put_sess_cmd(se_cmd);
transport_cmd_finish_abort(se_cmd, true);
+   target_put_sess_cmd(se_cmd);
 
printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
" ref_tag: %llu\n", ref_tag);
@@ -237,8 +257,10 @@ static void core_tmr_drain_state_list(
struct list_head *preempt_and_abort_list)
 {
LIST_HEAD(drain_task_list);
+   struct se_session *sess;
struct se_cmd *cmd, *next;
unsigned long flags;
+   int rc;
 
/*
 * Complete outstanding commands with TASK_ABORTED SAM status.
@@ -277,6 +299,17 @@ static void core_tmr_drain_state_list(
if (prout_cmd == cmd)