diff options
| author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-02-24 19:58:20 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2011-02-28 12:23:32 -0500 |
| commit | 52208ae3fc60cbcb214c10fb8b82304199e2cc3a (patch) | |
| tree | d7c7e938453b257ce49197cb91f64fed1860b254 | |
| parent | 493f3358cb289ccf716c5a14fa5bb52ab75943e5 (diff) | |
[SCSI] target: Fix t_transport_aborted handling in LUN_RESET + active I/O shutdown
This patch addresses two outstanding bugs related to
T_TASK(cmd)->t_transport_aborted handling during TMR LUN_RESET and
active I/O shutdown.
This first involves adding two explict t_transport_aborted=1
assignments in core_tmr_lun_reset() in order to signal the task has
been aborted, and updating transport_generic_wait_for_tasks() to skip
sleeping when t_transport_aborted=1 has been set. This fixes an issue
where transport_generic_wait_for_tasks() would end up sleeping
indefinately when called from fabric module context while TMR
LUN_RESET was happening with long outstanding backend struct se_task
not yet being completed.
The second adds a missing call to
transport_remove_task_from_execute_queue() when
task->task_execute_queue=1 is set in order to fix an OOPs when
task->t_execute_list has not been dropped. It also fixes the same
case in transport_processing_shutdown() to prevent the issue from
happening during active I/O struct se_device shutdown.
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
| -rw-r--r-- | drivers/target/target_core_tmr.c | 5 | ||||
| -rw-r--r-- | drivers/target/target_core_transport.c | 8 | ||||
| -rw-r--r-- | include/target/target_core_transport.h | 2 |
3 files changed, 13 insertions, 2 deletions
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 158cecbec718..4a109835e420 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
| @@ -282,6 +282,9 @@ int core_tmr_lun_reset( | |||
| 282 | 282 | ||
| 283 | atomic_set(&task->task_active, 0); | 283 | atomic_set(&task->task_active, 0); |
| 284 | atomic_set(&task->task_stop, 0); | 284 | atomic_set(&task->task_stop, 0); |
| 285 | } else { | ||
| 286 | if (atomic_read(&task->task_execute_queue) != 0) | ||
| 287 | transport_remove_task_from_execute_queue(task, dev); | ||
| 285 | } | 288 | } |
| 286 | __transport_stop_task_timer(task, &flags); | 289 | __transport_stop_task_timer(task, &flags); |
| 287 | 290 | ||
| @@ -301,6 +304,7 @@ int core_tmr_lun_reset( | |||
| 301 | DEBUG_LR("LUN_RESET: got t_transport_active = 1 for" | 304 | DEBUG_LR("LUN_RESET: got t_transport_active = 1 for" |
| 302 | " task: %p, t_fe_count: %d dev: %p\n", task, | 305 | " task: %p, t_fe_count: %d dev: %p\n", task, |
| 303 | fe_count, dev); | 306 | fe_count, dev); |
| 307 | atomic_set(&T_TASK(cmd)->t_transport_aborted, 1); | ||
| 304 | spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, | 308 | spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, |
| 305 | flags); | 309 | flags); |
| 306 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); | 310 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); |
| @@ -310,6 +314,7 @@ int core_tmr_lun_reset( | |||
| 310 | } | 314 | } |
| 311 | DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p," | 315 | DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p," |
| 312 | " t_fe_count: %d dev: %p\n", task, fe_count, dev); | 316 | " t_fe_count: %d dev: %p\n", task, fe_count, dev); |
| 317 | atomic_set(&T_TASK(cmd)->t_transport_aborted, 1); | ||
| 313 | spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); | 318 | spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); |
| 314 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); | 319 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); |
| 315 | 320 | ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 236e22d8cfae..4bbf6c147f89 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
| @@ -1207,7 +1207,7 @@ transport_get_task_from_execute_queue(struct se_device *dev) | |||
| 1207 | * | 1207 | * |
| 1208 | * | 1208 | * |
| 1209 | */ | 1209 | */ |
| 1210 | static void transport_remove_task_from_execute_queue( | 1210 | void transport_remove_task_from_execute_queue( |
| 1211 | struct se_task *task, | 1211 | struct se_task *task, |
| 1212 | struct se_device *dev) | 1212 | struct se_device *dev) |
| 1213 | { | 1213 | { |
| @@ -5549,7 +5549,8 @@ static void transport_generic_wait_for_tasks( | |||
| 5549 | 5549 | ||
| 5550 | atomic_set(&T_TASK(cmd)->transport_lun_stop, 0); | 5550 | atomic_set(&T_TASK(cmd)->transport_lun_stop, 0); |
| 5551 | } | 5551 | } |
| 5552 | if (!atomic_read(&T_TASK(cmd)->t_transport_active)) | 5552 | if (!atomic_read(&T_TASK(cmd)->t_transport_active) || |
| 5553 | atomic_read(&T_TASK(cmd)->t_transport_aborted)) | ||
| 5553 | goto remove; | 5554 | goto remove; |
| 5554 | 5555 | ||
| 5555 | atomic_set(&T_TASK(cmd)->t_transport_stop, 1); | 5556 | atomic_set(&T_TASK(cmd)->t_transport_stop, 1); |
| @@ -5956,6 +5957,9 @@ static void transport_processing_shutdown(struct se_device *dev) | |||
| 5956 | 5957 | ||
| 5957 | atomic_set(&task->task_active, 0); | 5958 | atomic_set(&task->task_active, 0); |
| 5958 | atomic_set(&task->task_stop, 0); | 5959 | atomic_set(&task->task_stop, 0); |
| 5960 | } else { | ||
| 5961 | if (atomic_read(&task->task_execute_queue) != 0) | ||
| 5962 | transport_remove_task_from_execute_queue(task, dev); | ||
| 5959 | } | 5963 | } |
| 5960 | __transport_stop_task_timer(task, &flags); | 5964 | __transport_stop_task_timer(task, &flags); |
| 5961 | 5965 | ||
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h index 246940511579..2e8ec51f0615 100644 --- a/include/target/target_core_transport.h +++ b/include/target/target_core_transport.h | |||
| @@ -135,6 +135,8 @@ extern void transport_complete_task(struct se_task *, int); | |||
| 135 | extern void transport_add_task_to_execute_queue(struct se_task *, | 135 | extern void transport_add_task_to_execute_queue(struct se_task *, |
| 136 | struct se_task *, | 136 | struct se_task *, |
| 137 | struct se_device *); | 137 | struct se_device *); |
| 138 | extern void transport_remove_task_from_execute_queue(struct se_task *, | ||
| 139 | struct se_device *); | ||
| 138 | unsigned char *transport_dump_cmd_direction(struct se_cmd *); | 140 | unsigned char *transport_dump_cmd_direction(struct se_cmd *); |
| 139 | extern void transport_dump_dev_state(struct se_device *, char *, int *); | 141 | extern void transport_dump_dev_state(struct se_device *, char *, int *); |
| 140 | extern void transport_dump_dev_info(struct se_device *, struct se_lun *, | 142 | extern void transport_dump_dev_info(struct se_device *, struct se_lun *, |
