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 /drivers/target | |
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>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_tmr.c | 5 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 8 |
2 files changed, 11 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 | ||