diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-02-05 17:51:36 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-02-06 18:59:38 -0500 |
commit | 310d3d314be7f0a84011ebdc4bdccbcae9755a87 (patch) | |
tree | a16767f7254b15213a1f4950765c88a60a347a1c | |
parent | 0f4a943168f31d29a1701908931acaba518b131a (diff) |
target: Fix race with SCF_SEND_DELAYED_TAS handling
This patch fixes a race between setting of SCF_SEND_DELAYED_TAS
in transport_send_task_abort(), and check of the same bit in
transport_check_aborted_status().
It adds a __transport_check_aborted_status() version that is
used by target_execute_cmd() when se_cmd->t_state_lock is
held, and a transport_check_aborted_status() wrapper for
all other existing callers.
Also, it handles the case where the check happens before
transport_send_task_abort() gets called. For this, go
ahead and set SCF_SEND_DELAYED_TAS early when necessary,
and have transport_send_task_abort() send the abort.
Cc: Quinn Tran <quinn.tran@qlogic.com>
Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Andy Grover <agrover@redhat.com>
Cc: Mike Christie <mchristi@redhat.com>
Cc: stable@vger.kernel.org # 3.10+
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_transport.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3441b159e306..2e0b23a3d5c4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -1858,19 +1858,21 @@ static bool target_handle_task_attr(struct se_cmd *cmd) | |||
1858 | return true; | 1858 | return true; |
1859 | } | 1859 | } |
1860 | 1860 | ||
1861 | static int __transport_check_aborted_status(struct se_cmd *, int); | ||
1862 | |||
1861 | void target_execute_cmd(struct se_cmd *cmd) | 1863 | void target_execute_cmd(struct se_cmd *cmd) |
1862 | { | 1864 | { |
1863 | /* | 1865 | /* |
1864 | * If the received CDB has aleady been aborted stop processing it here. | ||
1865 | */ | ||
1866 | if (transport_check_aborted_status(cmd, 1)) | ||
1867 | return; | ||
1868 | |||
1869 | /* | ||
1870 | * Determine if frontend context caller is requesting the stopping of | 1866 | * Determine if frontend context caller is requesting the stopping of |
1871 | * this command for frontend exceptions. | 1867 | * this command for frontend exceptions. |
1868 | * | ||
1869 | * If the received CDB has aleady been aborted stop processing it here. | ||
1872 | */ | 1870 | */ |
1873 | spin_lock_irq(&cmd->t_state_lock); | 1871 | spin_lock_irq(&cmd->t_state_lock); |
1872 | if (__transport_check_aborted_status(cmd, 1)) { | ||
1873 | spin_unlock_irq(&cmd->t_state_lock); | ||
1874 | return; | ||
1875 | } | ||
1874 | if (cmd->transport_state & CMD_T_STOP) { | 1876 | if (cmd->transport_state & CMD_T_STOP) { |
1875 | pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", | 1877 | pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", |
1876 | __func__, __LINE__, cmd->tag); | 1878 | __func__, __LINE__, cmd->tag); |
@@ -2911,28 +2913,49 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2911 | } | 2913 | } |
2912 | EXPORT_SYMBOL(transport_send_check_condition_and_sense); | 2914 | EXPORT_SYMBOL(transport_send_check_condition_and_sense); |
2913 | 2915 | ||
2914 | int transport_check_aborted_status(struct se_cmd *cmd, int send_status) | 2916 | static int __transport_check_aborted_status(struct se_cmd *cmd, int send_status) |
2917 | __releases(&cmd->t_state_lock) | ||
2918 | __acquires(&cmd->t_state_lock) | ||
2915 | { | 2919 | { |
2920 | assert_spin_locked(&cmd->t_state_lock); | ||
2921 | WARN_ON_ONCE(!irqs_disabled()); | ||
2922 | |||
2916 | if (!(cmd->transport_state & CMD_T_ABORTED)) | 2923 | if (!(cmd->transport_state & CMD_T_ABORTED)) |
2917 | return 0; | 2924 | return 0; |
2918 | |||
2919 | /* | 2925 | /* |
2920 | * If cmd has been aborted but either no status is to be sent or it has | 2926 | * If cmd has been aborted but either no status is to be sent or it has |
2921 | * already been sent, just return | 2927 | * already been sent, just return |
2922 | */ | 2928 | */ |
2923 | if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) | 2929 | if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) { |
2930 | if (send_status) | ||
2931 | cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; | ||
2924 | return 1; | 2932 | return 1; |
2933 | } | ||
2925 | 2934 | ||
2926 | pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n", | 2935 | pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB:" |
2927 | cmd->t_task_cdb[0], cmd->tag); | 2936 | " 0x%02x ITT: 0x%08llx\n", cmd->t_task_cdb[0], cmd->tag); |
2928 | 2937 | ||
2929 | cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; | 2938 | cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; |
2930 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; | 2939 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; |
2931 | trace_target_cmd_complete(cmd); | 2940 | trace_target_cmd_complete(cmd); |
2941 | |||
2942 | spin_unlock_irq(&cmd->t_state_lock); | ||
2932 | cmd->se_tfo->queue_status(cmd); | 2943 | cmd->se_tfo->queue_status(cmd); |
2944 | spin_lock_irq(&cmd->t_state_lock); | ||
2933 | 2945 | ||
2934 | return 1; | 2946 | return 1; |
2935 | } | 2947 | } |
2948 | |||
2949 | int transport_check_aborted_status(struct se_cmd *cmd, int send_status) | ||
2950 | { | ||
2951 | int ret; | ||
2952 | |||
2953 | spin_lock_irq(&cmd->t_state_lock); | ||
2954 | ret = __transport_check_aborted_status(cmd, send_status); | ||
2955 | spin_unlock_irq(&cmd->t_state_lock); | ||
2956 | |||
2957 | return ret; | ||
2958 | } | ||
2936 | EXPORT_SYMBOL(transport_check_aborted_status); | 2959 | EXPORT_SYMBOL(transport_check_aborted_status); |
2937 | 2960 | ||
2938 | void transport_send_task_abort(struct se_cmd *cmd) | 2961 | void transport_send_task_abort(struct se_cmd *cmd) |
@@ -2954,11 +2977,17 @@ void transport_send_task_abort(struct se_cmd *cmd) | |||
2954 | */ | 2977 | */ |
2955 | if (cmd->data_direction == DMA_TO_DEVICE) { | 2978 | if (cmd->data_direction == DMA_TO_DEVICE) { |
2956 | if (cmd->se_tfo->write_pending_status(cmd) != 0) { | 2979 | if (cmd->se_tfo->write_pending_status(cmd) != 0) { |
2957 | cmd->transport_state |= CMD_T_ABORTED; | 2980 | spin_lock_irqsave(&cmd->t_state_lock, flags); |
2981 | if (cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS) { | ||
2982 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
2983 | goto send_abort; | ||
2984 | } | ||
2958 | cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; | 2985 | cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; |
2986 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
2959 | return; | 2987 | return; |
2960 | } | 2988 | } |
2961 | } | 2989 | } |
2990 | send_abort: | ||
2962 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; | 2991 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; |
2963 | 2992 | ||
2964 | transport_lun_remove_cmd(cmd); | 2993 | transport_lun_remove_cmd(cmd); |