diff mbox

[09/34] target: Make it possible to specify I_T nexus for SCSI abort

Message ID 20170125233646.2243-10-bart.vanassche@sandisk.com (mailing list archive)
State Superseded
Headers show

Commit Message

Bart Van Assche Jan. 25, 2017, 11:36 p.m. UTC
target_submit_tmr() only supports the I_T_L nexus for SCSI abort
and other task management functions. Make it possible for target
drivers to specify I_T nexus for SCSI abort by passing the
TARGET_SCF_IGNORE_TMR_LUN flag to target_submit_tmr().

Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Himanshu Madhani <himanshu.madhani@cavium.com>
Cc: Giridhar Malavali <giridhar.malavali@cavium.com>
---
 drivers/target/target_core_tmr.c       | 16 +++++++++++++++-
 drivers/target/target_core_transport.c | 23 +++++++++++++++++------
 include/target/target_core_base.h      |  1 +
 3 files changed, 33 insertions(+), 7 deletions(-)

Comments

Hannes Reinecke Jan. 26, 2017, 7:49 a.m. UTC | #1
On 01/26/2017 12:36 AM, Bart Van Assche wrote:
> target_submit_tmr() only supports the I_T_L nexus for SCSI abort
> and other task management functions. Make it possible for target
> drivers to specify I_T nexus for SCSI abort by passing the
> TARGET_SCF_IGNORE_TMR_LUN flag to target_submit_tmr().
> 
> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Himanshu Madhani <himanshu.madhani@cavium.com>
> Cc: Giridhar Malavali <giridhar.malavali@cavium.com>
> ---
>  drivers/target/target_core_tmr.c       | 16 +++++++++++++++-
>  drivers/target/target_core_transport.c | 23 +++++++++++++++++------
>  include/target/target_core_base.h      |  1 +
>  3 files changed, 33 insertions(+), 7 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
Christoph Hellwig Jan. 26, 2017, 5:31 p.m. UTC | #2
> -	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
> +	if (cmd->se_dev)
> +		queue_work(cmd->se_dev->tmr_wq, &cmd->work);
> +	else
> +		schedule_work(&cmd->work);

This looks suspicious. se_dev->tmr_wq has the WQ_MEM_RECLAIM flag set, so
it always has a rescuer thread available, while the generic system work
queue is just a best effort.  Additional a unbound wq with max_active of
guarantees strict execution ordering.  I don't even know if the code
relies on this fact, but changing it should require an explanation of why
that change is fine.
--
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
Bart Van Assche Jan. 30, 2017, 9:42 p.m. UTC | #3
On Thu, 2017-01-26 at 09:31 -0800, Christoph Hellwig wrote:
> > -	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
> > +	if (cmd->se_dev)
> > +		queue_work(cmd->se_dev->tmr_wq, &cmd->work);
> > +	else
> > +		schedule_work(&cmd->work);
> 
> This looks suspicious. se_dev->tmr_wq has the WQ_MEM_RECLAIM flag set, so
> it always has a rescuer thread available, while the generic system work
> queue is just a best effort.  Additional a unbound wq with max_active of
> guarantees strict execution ordering.  I don't even know if the code
> relies on this fact, but changing it should require an explanation of why
> that change is fine.

Hello Christoph,

Maybe I overlooked something but I haven't found any clause in SAM-5 that
specifies in which order task management functions should be executed. But
I will add a comment in the code that explains this.

Regarding WQ_MEM_RECLAIM: that flag guarantees that there is at least one
execution context regardless of memory pressure. So enabling that flag is
essential for any workqueue that executes work inside the memory reclaim
path. The only way the above code can be called from inside a block device
implementation is if it gets called by the tcm_loop driver. However, I'm
not sure anyone is using the tcm_loop driver for another purpose than
testing the LIO core and backend drivers?

Bart.--
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
Christoph Hellwig Jan. 31, 2017, 2:44 p.m. UTC | #4
On Mon, Jan 30, 2017 at 09:42:50PM +0000, Bart Van Assche wrote:
> Maybe I overlooked something but I haven't found any clause in SAM-5 that
> specifies in which order task management functions should be executed. But
> I will add a comment in the code that explains this.

It's just my unexplained change detector that went off.  However if
we don't need the separate workqueue to start with it would be a good
preparational patch to remove it.

The workqueue was added by me in 2012 and replaced a kthread - the
commit log mentions it uses a singlethreaded workqueue to keep the
semantics exactly the same as before.
--
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
Bart Van Assche Jan. 31, 2017, 6:51 p.m. UTC | #5
On Tue, 2017-01-31 at 15:44 +0100, hch@lst.de wrote:
> On Mon, Jan 30, 2017 at 09:42:50PM +0000, Bart Van Assche wrote:
> > Maybe I overlooked something but I haven't found any clause in SAM-5 that
> > specifies in which order task management functions should be executed. But
> > I will add a comment in the code that explains this.
> 
> It's just my unexplained change detector that went off.  However if
> we don't need the separate workqueue to start with it would be a good
> preparational patch to remove it.
> 
> The workqueue was added by me in 2012 and replaced a kthread - the
> commit log mentions it uses a singlethreaded workqueue to keep the
> semantics exactly the same as before.

Hello Christoph,

The SCSI target ALUA code uses tmr_wq to ensure that ALUA transitions
are executed in the same order as the core_alua_do_transition_tg_pt()
calls that triggered these transitions. So I'm not sure we can get rid
of tmr_wq without rewriting the ALUA code. But I can modify the TMR
code such that it always uses schedule_work() and hence doesn't need
tmr_wq anymore.

Bart.--
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
Christoph Hellwig Jan. 31, 2017, 8:39 p.m. UTC | #6
On Tue, Jan 31, 2017 at 06:51:02PM +0000, Bart Van Assche wrote:
> Hello Christoph,
> 
> The SCSI target ALUA code uses tmr_wq to ensure that ALUA transitions
> are executed in the same order as the core_alua_do_transition_tg_pt()
> calls that triggered these transitions. So I'm not sure we can get rid
> of tmr_wq without rewriting the ALUA code. But I can modify the TMR
> code such that it always uses schedule_work() and hence doesn't need
> tmr_wq anymore.

Switching the TMR code to use schedule_work and then renaming tmr_wq
sounds fine to me.
--
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
Mike Christie Jan. 31, 2017, 8:46 p.m. UTC | #7
On 01/30/2017 03:42 PM, Bart Van Assche wrote:
> On Thu, 2017-01-26 at 09:31 -0800, Christoph Hellwig wrote:
>>> -	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
>>> +	if (cmd->se_dev)
>>> +		queue_work(cmd->se_dev->tmr_wq, &cmd->work);
>>> +	else
>>> +		schedule_work(&cmd->work);
>>
>> This looks suspicious. se_dev->tmr_wq has the WQ_MEM_RECLAIM flag set, so
>> it always has a rescuer thread available, while the generic system work
>> queue is just a best effort.  Additional a unbound wq with max_active of
>> guarantees strict execution ordering.  I don't even know if the code
>> relies on this fact, but changing it should require an explanation of why
>> that change is fine.
> 
> Hello Christoph,
> 
> Maybe I overlooked something but I haven't found any clause in SAM-5 that
> specifies in which order task management functions should be executed. But
> I will add a comment in the code that explains this.


Does it depend on the transport?

I am not sure if it is the same thing, but 6.3.3 in SAM says a LU RESET
would need to terminate all other TMFs that were executing. And for
iscsi, a LU RESET and ABORT TASK SET with a cmd sequence number N is
supposed to terminate tasks and TMFs with cmd sequence numbers N - 1,
and iscsi also says that if a TMF has terminated a task/TMF then the
target cannot send responses for it.

So I think we have execute them in order or make it look like they did.
The drain call does though right?
--
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
Bart Van Assche Jan. 31, 2017, 9:22 p.m. UTC | #8
On Tue, 2017-01-31 at 14:46 -0600, Mike Christie wrote:
> On 01/30/2017 03:42 PM, Bart Van Assche wrote:
> > Maybe I overlooked something but I haven't found any clause in SAM-5 that
> > specifies in which order task management functions should be executed. But
> > I will add a comment in the code that explains this.
> 
> Does it depend on the transport?
> 
> I am not sure if it is the same thing, but 6.3.3 in SAM says a LU RESET
> would need to terminate all other TMFs that were executing. And for
> iscsi, a LU RESET and ABORT TASK SET with a cmd sequence number N is
> supposed to terminate tasks and TMFs with cmd sequence numbers N - 1,
> and iscsi also says that if a TMF has terminated a task/TMF then the
> target cannot send responses for it.
> 
> So I think we have execute them in order or make it look like they did.
> The drain call does though right?

I'm not sure the drain call guarantees this for TMFs that affect multiple
logical units since today there is one WQ per logical unit.

Since SCSI transport layers that require that the transport layer delivers
TMFs in the same order as submitted by the initiator I think this means
that we need one WQ per I_T nexus for TMFs instead of one per device to be
able to implement TARGET_SCF_IGNORE_TMR_LUN.

Bart.--
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
Michael Cyr Jan. 31, 2017, 9:26 p.m. UTC | #9
On 1/31/17 2:46 PM, Mike Christie wrote:

> On 01/30/2017 03:42 PM, Bart Van Assche wrote:
>> On Thu, 2017-01-26 at 09:31 -0800, Christoph Hellwig wrote:
>>>> -	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
>>>> +	if (cmd->se_dev)
>>>> +		queue_work(cmd->se_dev->tmr_wq, &cmd->work);
>>>> +	else
>>>> +		schedule_work(&cmd->work);
>>> This looks suspicious. se_dev->tmr_wq has the WQ_MEM_RECLAIM flag set, so
>>> it always has a rescuer thread available, while the generic system work
>>> queue is just a best effort.  Additional a unbound wq with max_active of
>>> guarantees strict execution ordering.  I don't even know if the code
>>> relies on this fact, but changing it should require an explanation of why
>>> that change is fine.
>> Hello Christoph,
>>
>> Maybe I overlooked something but I haven't found any clause in SAM-5 that
>> specifies in which order task management functions should be executed. But
>> I will add a comment in the code that explains this.
>
> Does it depend on the transport?
>
> I am not sure if it is the same thing, but 6.3.3 in SAM says a LU RESET
> would need to terminate all other TMFs that were executing. And for
> iscsi, a LU RESET and ABORT TASK SET with a cmd sequence number N is
> supposed to terminate tasks and TMFs with cmd sequence numbers N - 1,
> and iscsi also says that if a TMF has terminated a task/TMF then the
> target cannot send responses for it.
>
> So I think we have execute them in order or make it look like they did.
> The drain call does though right?
> --
> 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
Most of the cases you cite specify interactions between a TMF and 
commands, not other TMFs (except for the LU Reset case).

More specifically, section 4.4.3 in SAM says "The order in which task 
management requests are processed is not specified by the SCSI 
architecture model. The SCSI architecture model does not require 
in-order delivery of task management requests or processing by the task 
manager in the order received."

--
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
diff mbox

Patch

diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 311dc3c2f1dc..367799b4dde1 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -149,6 +149,13 @@  static bool __target_check_io_state(struct se_cmd *se_cmd,
 	return kref_get_unless_zero(&se_cmd->cmd_kref);
 }
 
+/**
+ * core_tmr_abort_task - abort a SCSI command
+ * @dev: LUN specified in task management function or NULL if no LUN has been
+ *	 specified.
+ * @tmr: Task management function.
+ * @se_sess: Session a.k.a. I_T nexus.
+ */
 void core_tmr_abort_task(
 	struct se_device *dev,
 	struct se_tmr_req *tmr,
@@ -161,7 +168,7 @@  void core_tmr_abort_task(
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 	list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) {
 
-		if (dev != se_cmd->se_dev)
+		if (dev && dev != se_cmd->se_dev)
 			continue;
 
 		/* skip task management functions, including tmr->task_cmd */
@@ -178,6 +185,13 @@  void core_tmr_abort_task(
 		if (!__target_check_io_state(se_cmd, se_sess, 0))
 			continue;
 
+		if (!tmr->tmr_dev &&
+		    transport_lookup_tmr_lun(tmr->task_cmd,
+					     se_cmd->orig_fe_lun) < 0) {
+			target_put_sess_cmd(se_cmd);
+			continue;
+		}
+
 		list_del_init(&se_cmd->se_cmd_list);
 		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 1cadc9eefa21..9b1dced4534a 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1584,18 +1584,18 @@  static void target_complete_tmr_failure(struct work_struct *work)
 }
 
 /**
- * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd
- *                     for TMR CDBs
+ * target_submit_tmr - submit a SCSI task management function to the target core
  *
  * @se_cmd: command descriptor to submit
  * @se_sess: associated se_sess for endpoint
  * @sense: pointer to SCSI sense buffer
- * @unpacked_lun: unpacked LUN to reference for struct se_lun
+ * @unpacked_lun: LUN the TMR applies to. Ignored if TARGET_SCF_IGNORE_TMR_LUN
+ *	has been set in @flags.
  * @fabric_context: fabric context for TMR req
  * @tm_type: Type of TM request
  * @gfp: gfp type for caller
  * @tag: referenced task tag for TMR_ABORT_TASK
- * @flags: submit cmd flags
+ * @flags: submit cmd flags (TARGET_SCF_*).
  *
  * Callable from all contexts.
  **/
@@ -1631,7 +1631,14 @@  int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
 		return ret;
 	}
 
-	ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun);
+	if (flags & TARGET_SCF_IGNORE_TMR_LUN) {
+		WARN_ON_ONCE(tm_type != TMR_ABORT_TASK);
+		se_cmd->se_lun = NULL;
+		se_cmd->se_dev = NULL;
+		se_cmd->se_tmr_req->tmr_dev = NULL;
+	} else {
+		ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun);
+	}
 	if (ret) {
 		/*
 		 * For callback during failure handling, push this work off
@@ -1641,6 +1648,7 @@  int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
 		schedule_work(&se_cmd->work);
 		return 0;
 	}
+	WARN_ON_ONCE(tm_type != TMR_ABORT_TASK && !se_cmd->se_dev);
 	transport_generic_handle_tmr(se_cmd);
 	return 0;
 }
@@ -3129,7 +3137,10 @@  int transport_generic_handle_tmr(
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 	INIT_WORK(&cmd->work, target_tmr_work);
-	queue_work(cmd->se_dev->tmr_wq, &cmd->work);
+	if (cmd->se_dev)
+		queue_work(cmd->se_dev->tmr_wq, &cmd->work);
+	else
+		schedule_work(&cmd->work);
 	return 0;
 }
 EXPORT_SYMBOL(transport_generic_handle_tmr);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index fc52207e8076..b953ad635929 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -186,6 +186,7 @@  enum target_sc_flags_table {
 	TARGET_SCF_ACK_KREF		= 0x02,
 	TARGET_SCF_UNKNOWN_SIZE		= 0x04,
 	TARGET_SCF_USE_CPUID	= 0x08,
+	TARGET_SCF_IGNORE_TMR_LUN	= 0x10,
 };
 
 /* fabric independent task management function values */