aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2011-05-19 23:19:11 -0400
committerJames Bottomley <jbottomley@parallels.com>2011-05-24 13:00:10 -0400
commitf436677262a5b524ac87675014c6d4e8ee153029 (patch)
treec3ab2fb111163ac52eb4999b83d3063ca4fca718
parent53ab6709b4d35b1924240854d794482fd7d33d4a (diff)
[SCSI] target: Fix bug with task_sg chained transport_free_dev_tasks release
This patch addresses a bug in the target core release path for HW operation where transport_free_dev_tasks() was incorrectly being called from transport_lun_remove_cmd() while releasing a se_cmd reference and calling struct target_core_fabric_ops->queue_data_in(). This would result in a OOPs with HW target mode when the release of se_task->task_sg[] would happen before pci_unmap_sg() can be called in HW target mode fabric module code. This patch addresses the issue by moving transport_free_dev_tasks() from transport_lun_remove_cmd() into transport_generic_free_cmd(), and adding TRANSPORT_FREE_CMD_INTR and transport_generic_free_cmd_intr() to allow se_cmd descriptor release to happen fromfrom within transport_processing_thread() process context when release of se_cmd is not possible from HW interrupt context. Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> Cc: stable@kernel.org Signed-off-by: James Bottomley <jbottomley@parallels.com>
-rw-r--r--drivers/target/target_core_transport.c13
-rw-r--r--include/target/target_core_base.h1
-rw-r--r--include/target/target_core_transport.h1
3 files changed, 14 insertions, 1 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 833060e0de5..7c87b042375 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -762,7 +762,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
762 transport_all_task_dev_remove_state(cmd); 762 transport_all_task_dev_remove_state(cmd);
763 spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); 763 spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
764 764
765 transport_free_dev_tasks(cmd);
766 765
767check_lun: 766check_lun:
768 spin_lock_irqsave(&lun->lun_cmd_lock, flags); 767 spin_lock_irqsave(&lun->lun_cmd_lock, flags);
@@ -2058,6 +2057,13 @@ int transport_generic_handle_tmr(
2058} 2057}
2059EXPORT_SYMBOL(transport_generic_handle_tmr); 2058EXPORT_SYMBOL(transport_generic_handle_tmr);
2060 2059
2060void transport_generic_free_cmd_intr(
2061 struct se_cmd *cmd)
2062{
2063 transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR);
2064}
2065EXPORT_SYMBOL(transport_generic_free_cmd_intr);
2066
2061static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) 2067static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
2062{ 2068{
2063 struct se_task *task, *task_tmp; 2069 struct se_task *task, *task_tmp;
@@ -5301,6 +5307,8 @@ void transport_generic_free_cmd(
5301 if (wait_for_tasks && cmd->transport_wait_for_tasks) 5307 if (wait_for_tasks && cmd->transport_wait_for_tasks)
5302 cmd->transport_wait_for_tasks(cmd, 0, 0); 5308 cmd->transport_wait_for_tasks(cmd, 0, 0);
5303 5309
5310 transport_free_dev_tasks(cmd);
5311
5304 transport_generic_remove(cmd, release_to_pool, 5312 transport_generic_remove(cmd, release_to_pool,
5305 session_reinstatement); 5313 session_reinstatement);
5306 } 5314 }
@@ -6136,6 +6144,9 @@ get_cmd:
6136 case TRANSPORT_REMOVE: 6144 case TRANSPORT_REMOVE:
6137 transport_generic_remove(cmd, 1, 0); 6145 transport_generic_remove(cmd, 1, 0);
6138 break; 6146 break;
6147 case TRANSPORT_FREE_CMD_INTR:
6148 transport_generic_free_cmd(cmd, 0, 1, 0);
6149 break;
6139 case TRANSPORT_PROCESS_TMR: 6150 case TRANSPORT_PROCESS_TMR:
6140 transport_generic_do_tmr(cmd); 6151 transport_generic_do_tmr(cmd);
6141 break; 6152 break;
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 1d3b5b2f0db..561ac99def5 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -98,6 +98,7 @@ enum transport_state_table {
98 TRANSPORT_REMOVE = 14, 98 TRANSPORT_REMOVE = 14,
99 TRANSPORT_FREE = 15, 99 TRANSPORT_FREE = 15,
100 TRANSPORT_NEW_CMD_MAP = 16, 100 TRANSPORT_NEW_CMD_MAP = 16,
101 TRANSPORT_FREE_CMD_INTR = 17,
101}; 102};
102 103
103/* Used for struct se_cmd->se_cmd_flags */ 104/* Used for struct se_cmd->se_cmd_flags */
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
index 59aa464f6ee..24a1c6cb83c 100644
--- a/include/target/target_core_transport.h
+++ b/include/target/target_core_transport.h
@@ -172,6 +172,7 @@ extern int transport_generic_handle_cdb_map(struct se_cmd *);
172extern int transport_generic_handle_data(struct se_cmd *); 172extern int transport_generic_handle_data(struct se_cmd *);
173extern void transport_new_cmd_failure(struct se_cmd *); 173extern void transport_new_cmd_failure(struct se_cmd *);
174extern int transport_generic_handle_tmr(struct se_cmd *); 174extern int transport_generic_handle_tmr(struct se_cmd *);
175extern void transport_generic_free_cmd_intr(struct se_cmd *);
175extern void __transport_stop_task_timer(struct se_task *, unsigned long *); 176extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
176extern unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]); 177extern unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]);
177extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, 178extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,