Re: Task Management handling and TAS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Nicholas,

On 3/18/14, 10:04 PM, Nicholas A. Bellinger wrote:
> On Mon, 2014-03-17 at 19:57 -0700, Alex Leung wrote:
>> On 3/17/14, 11:56 AM, Nicholas A. Bellinger wrote:
>>
>> <SNIP>
>>
>>> Here's an updated patch to drop the transport_send_task_abort() in
>>> core_tmr_abort_task(), and add the transport_cmd_finish_abort() to make
>>> the final target_put_sess_cmd(), invoking TFO->release_cmd() to release
>>> the associated descriptor.
>>>
>>> Care to test..?  ;)
>>
>> I'd be happy to -- just give me a day or two. I assume it's okay that
>> I'll be testing with a non-upstream fabric driver (Emulex OCS SDK)?
>>
> 
> For this particular patch that's fine, and I'll also confirm the change
> with a couple of other fabric drivers before pushing.

I did some testing with your most recent patch applied to the "for-next"
branch and the following now results in the tfo->release_cmd() path 
instead of the tfo->queue_status() with TASK_ABORTED status path. 

1. Abort Task
2. LUN Reset with TAS=0 
3. LUN Reset with TAS=1 but IT Nexus(cmd) matches IT Nexus(tmr)

To test TAS=1 where the IT Nexuses do not match, I did not have another 
initiator handy, so I took a shortcut and changed the 
core_tmr_handle_tas_abort() to just be "if (tas)" (removing the IT Nexus
not matching qualifier) and made sure that tfo->queue_status 
(TASK_ABORTED) was called -- it was.

So far, so good.

However, it looks transport_check_aborted_status() is also not quite
right. Currently it calls tfo->queue_status() with the TASK_ABORTED 
status regardless of TAS and Abort Task v. LUN Reset. I can fabricate 
a race condition where, just before tfo->release_cmd() is called 
for the abort, the write data phase completes and calls 
target_execute_cmd() (which calls transport_check_aborted_status(), 
which calls tfo->queue_status()). 

I believe transport_check_aborted_status() is for the case where 
transport_send_task_abort() is called but the fabric driver is not 
ready to send the response, so it returns non-zero for 
tfo->write_pending_status(). When the dataphase is complete, 
target_execute_cmd() --> transport_check_aborted_status() is called. 
If my understanding correct, it seems like CMD_T_ABORTED has
two meanings: 1. the command has been aborted and 2. we wish to send
a task aborted status at a later time (when the data phase has 
completed). If we use an se_cmd_flag to distinguish the aborted w/ 
TASK_ABORTED case from the aborted w/o TASK_ABORTED case, we would not 
send an unexpected tfo->queue_status (TASK_ABORTED) in the above case. 
The below patch (that includes your changes) works in this case (and 
still sends the delayed TASK_ABORTED when appropriate). Thoughts?

> 
> Also out of curiosity, what are the plans for this work wrt to
> mainline..?

Not sure I understand your question. Do you mean, what will we do wrt 
TMR/TAS etc. for current kernel versions (that use the queue_status() 
path)?

Thanks,
Alex


diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 70c638f..9f1dd53 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -87,14 +87,21 @@ static void core_tmr_handle_tas_abort(
        struct se_cmd *cmd,
        int tas)
 {
+       bool remove = true;
        /*
         * TASK ABORTED status (TAS) bit support
        */
        if ((tmr_nacl &&
-            (tmr_nacl == cmd->se_sess->se_node_acl)) || tas)
+            (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
+               remove = false;
                transport_send_task_abort(cmd);
+       }

-       transport_cmd_finish_abort(cmd, 0);
+       transport_cmd_finish_abort(cmd, remove);
 }

 static int target_check_cdb_and_preempt(struct list_head *list,
@@ -151,17 +158,13 @@ void core_tmr_abort_task(
                cancel_work_sync(&se_cmd->work);
                transport_wait_for_tasks(se_cmd);
                /*
-                * Now send SAM_STAT_TASK_ABORTED status for the referenced
-                * se_cmd descriptor..
-                */
-               transport_send_task_abort(se_cmd);
-               /*
                 * Also deal with possible extra acknowledge reference..
                 */
                if (se_cmd->se_cmd_flags & SCF_ACK_KREF)
                        target_put_sess_cmd(se_sess, se_cmd);

                target_put_sess_cmd(se_sess, se_cmd);
+               transport_cmd_finish_abort(se_cmd, true);

                printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
                                " ref_tag: %d\n", ref_tag);

diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 0a359fa..4bdcd14 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -603,6 +603,9 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)

 void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 {
+       if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
+               transport_lun_remove_cmd(cmd);
+
        if (transport_cmd_check_stop_to_fabric(cmd))
                return;
        if (remove)
@@ -2784,13 +2787,16 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
        if (!(cmd->transport_state & CMD_T_ABORTED))
                return 0;

-       if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS))
+       /* if cmd has been aborted but either no status is to be sent or it has
+        * already been sent, just return
+        */
+       if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS))
                return 1;

        pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n",
                 cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd));

-       cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
+       cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS;
        cmd->scsi_status = SAM_STAT_TASK_ABORTED;
        trace_target_cmd_complete(cmd);
        cmd->se_tfo->queue_status(cmd);
@@ -2804,7 +2810,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
        unsigned long flags;

        spin_lock_irqsave(&cmd->t_state_lock, flags);
-       if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) {
+       if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION)) {
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
                return;
        }
@@ -2819,6 +2825,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
        if (cmd->data_direction == DMA_TO_DEVICE) {
                if (cmd->se_tfo->write_pending_status(cmd) != 0) {
                        cmd->transport_state |= CMD_T_ABORTED;
+                       cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
                        smp_mb__after_atomic_inc();
                        return;
                }

diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index f13fd09..ec3e3a3 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -162,7 +162,7 @@ enum se_cmd_flags_table {
        SCF_SENT_CHECK_CONDITION        = 0x00000800,
        SCF_OVERFLOW_BIT                = 0x00001000,
        SCF_UNDERFLOW_BIT               = 0x00002000,
-       SCF_SENT_DELAYED_TAS            = 0x00004000,
+       SCF_SEND_DELAYED_TAS            = 0x00004000,
        SCF_ALUA_NON_OPTIMIZED          = 0x00008000,
        SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
        SCF_ACK_KREF                    = 0x00040000,




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




[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux