aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2016-05-18 01:19:10 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2016-07-20 03:58:38 -0400
commitdff0ca9ea7dc8be2181a62df4a722c32ce68ff4a (patch)
tree5a8fad3a30d78857da00f4be6952c4f16c95f35c
parentea263c7fada4af8ec7fe5fcfd6e7d7705a89351b (diff)
target: Fix ordered task target_setup_cmd_from_cdb exception hang
If a command with a Simple task attribute is failed due to a Unit Attention, then a subsequent command with an Ordered task attribute will hang forever. The reason for this is that the Unit Attention status is checked for in target_setup_cmd_from_cdb, before the call to target_execute_cmd, which calls target_handle_task_attr, which in turn increments dev->simple_cmds. However, transport_generic_request_failure still calls transport_complete_task_attr, which will decrement dev->simple_cmds. In this case, simple_cmds is now -1. So when a command with the Ordered task attribute is sent, target_handle_task_attr sees that dev->simple_cmds is not 0, so it decides it can't execute the command until all the (nonexistent) Simple commands have completed. Reported-by: Michael Cyr <mikecyr@linux.vnet.ibm.com> Tested-by: Michael Cyr <mikecyr@linux.vnet.ibm.com> Reported-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com> Tested-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com> Cc: stable@vger.kernel.org # 4.4+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_internal.h1
-rw-r--r--drivers/target/target_core_sbc.c2
-rw-r--r--drivers/target/target_core_transport.c62
-rw-r--r--include/target/target_core_fabric.h1
4 files changed, 37 insertions, 29 deletions
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index fc91e85f54ba..e2c970a9d61c 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -146,6 +146,7 @@ sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
146void target_qf_do_work(struct work_struct *work); 146void target_qf_do_work(struct work_struct *work);
147bool target_check_wce(struct se_device *dev); 147bool target_check_wce(struct se_device *dev);
148bool target_check_fua(struct se_device *dev); 148bool target_check_fua(struct se_device *dev);
149void __target_execute_cmd(struct se_cmd *, bool);
149 150
150/* target_core_stat.c */ 151/* target_core_stat.c */
151void target_stat_setup_dev_default_groups(struct se_device *); 152void target_stat_setup_dev_default_groups(struct se_device *);
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index a9057aa07176..04f616b3ba0a 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -602,7 +602,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
602 cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT; 602 cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
603 spin_unlock_irq(&cmd->t_state_lock); 603 spin_unlock_irq(&cmd->t_state_lock);
604 604
605 __target_execute_cmd(cmd); 605 __target_execute_cmd(cmd, false);
606 606
607 kfree(buf); 607 kfree(buf);
608 return ret; 608 return ret;
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 38bf2dcf926a..a6e1edcfefbd 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1303,23 +1303,6 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
1303 1303
1304 trace_target_sequencer_start(cmd); 1304 trace_target_sequencer_start(cmd);
1305 1305
1306 /*
1307 * Check for an existing UNIT ATTENTION condition
1308 */
1309 ret = target_scsi3_ua_check(cmd);
1310 if (ret)
1311 return ret;
1312
1313 ret = target_alua_state_check(cmd);
1314 if (ret)
1315 return ret;
1316
1317 ret = target_check_reservation(cmd);
1318 if (ret) {
1319 cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
1320 return ret;
1321 }
1322
1323 ret = dev->transport->parse_cdb(cmd); 1306 ret = dev->transport->parse_cdb(cmd);
1324 if (ret == TCM_UNSUPPORTED_SCSI_OPCODE) 1307 if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
1325 pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n", 1308 pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
@@ -1761,20 +1744,45 @@ queue_full:
1761} 1744}
1762EXPORT_SYMBOL(transport_generic_request_failure); 1745EXPORT_SYMBOL(transport_generic_request_failure);
1763 1746
1764void __target_execute_cmd(struct se_cmd *cmd) 1747void __target_execute_cmd(struct se_cmd *cmd, bool do_checks)
1765{ 1748{
1766 sense_reason_t ret; 1749 sense_reason_t ret;
1767 1750
1768 if (cmd->execute_cmd) { 1751 if (!cmd->execute_cmd) {
1769 ret = cmd->execute_cmd(cmd); 1752 ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
1770 if (ret) { 1753 goto err;
1771 spin_lock_irq(&cmd->t_state_lock); 1754 }
1772 cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT); 1755 if (do_checks) {
1773 spin_unlock_irq(&cmd->t_state_lock); 1756 /*
1757 * Check for an existing UNIT ATTENTION condition after
1758 * target_handle_task_attr() has done SAM task attr
1759 * checking, and possibly have already defered execution
1760 * out to target_restart_delayed_cmds() context.
1761 */
1762 ret = target_scsi3_ua_check(cmd);
1763 if (ret)
1764 goto err;
1765
1766 ret = target_alua_state_check(cmd);
1767 if (ret)
1768 goto err;
1774 1769
1775 transport_generic_request_failure(cmd, ret); 1770 ret = target_check_reservation(cmd);
1771 if (ret) {
1772 cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
1773 goto err;
1776 } 1774 }
1777 } 1775 }
1776
1777 ret = cmd->execute_cmd(cmd);
1778 if (!ret)
1779 return;
1780err:
1781 spin_lock_irq(&cmd->t_state_lock);
1782 cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
1783 spin_unlock_irq(&cmd->t_state_lock);
1784
1785 transport_generic_request_failure(cmd, ret);
1778} 1786}
1779 1787
1780static int target_write_prot_action(struct se_cmd *cmd) 1788static int target_write_prot_action(struct se_cmd *cmd)
@@ -1899,7 +1907,7 @@ void target_execute_cmd(struct se_cmd *cmd)
1899 return; 1907 return;
1900 } 1908 }
1901 1909
1902 __target_execute_cmd(cmd); 1910 __target_execute_cmd(cmd, true);
1903} 1911}
1904EXPORT_SYMBOL(target_execute_cmd); 1912EXPORT_SYMBOL(target_execute_cmd);
1905 1913
@@ -1923,7 +1931,7 @@ static void target_restart_delayed_cmds(struct se_device *dev)
1923 list_del(&cmd->se_delayed_node); 1931 list_del(&cmd->se_delayed_node);
1924 spin_unlock(&dev->delayed_cmd_lock); 1932 spin_unlock(&dev->delayed_cmd_lock);
1925 1933
1926 __target_execute_cmd(cmd); 1934 __target_execute_cmd(cmd, true);
1927 1935
1928 if (cmd->sam_task_attr == TCM_ORDERED_TAG) 1936 if (cmd->sam_task_attr == TCM_ORDERED_TAG)
1929 break; 1937 break;
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index de44462a7680..5cd6faa6e0d1 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -163,7 +163,6 @@ int core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
163void core_tmr_release_req(struct se_tmr_req *); 163void core_tmr_release_req(struct se_tmr_req *);
164int transport_generic_handle_tmr(struct se_cmd *); 164int transport_generic_handle_tmr(struct se_cmd *);
165void transport_generic_request_failure(struct se_cmd *, sense_reason_t); 165void transport_generic_request_failure(struct se_cmd *, sense_reason_t);
166void __target_execute_cmd(struct se_cmd *);
167int transport_lookup_tmr_lun(struct se_cmd *, u64); 166int transport_lookup_tmr_lun(struct se_cmd *, u64);
168void core_allocate_nexus_loss_ua(struct se_node_acl *acl); 167void core_allocate_nexus_loss_ua(struct se_node_acl *acl);
169 168