Commit 52208ae3fc60cbcb214c10fb8b82304199e2cc3a
Committed by
James Bottomley
1 parent
493f3358cb
Exists in
master
and in
7 other branches
[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>
Showing 3 changed files with 13 additions and 2 deletions Side-by-side Diff
drivers/target/target_core_tmr.c
... | ... | @@ -282,6 +282,9 @@ |
282 | 282 | |
283 | 283 | atomic_set(&task->task_active, 0); |
284 | 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 | 289 | __transport_stop_task_timer(task, &flags); |
287 | 290 | |
... | ... | @@ -301,6 +304,7 @@ |
301 | 304 | DEBUG_LR("LUN_RESET: got t_transport_active = 1 for" |
302 | 305 | " task: %p, t_fe_count: %d dev: %p\n", task, |
303 | 306 | fe_count, dev); |
307 | + atomic_set(&T_TASK(cmd)->t_transport_aborted, 1); | |
304 | 308 | spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, |
305 | 309 | flags); |
306 | 310 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); |
... | ... | @@ -310,6 +314,7 @@ |
310 | 314 | } |
311 | 315 | DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p," |
312 | 316 | " t_fe_count: %d dev: %p\n", task, fe_count, dev); |
317 | + atomic_set(&T_TASK(cmd)->t_transport_aborted, 1); | |
313 | 318 | spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); |
314 | 319 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); |
315 | 320 |
drivers/target/target_core_transport.c
... | ... | @@ -1207,7 +1207,7 @@ |
1207 | 1207 | * |
1208 | 1208 | * |
1209 | 1209 | */ |
1210 | -static void transport_remove_task_from_execute_queue( | |
1210 | +void transport_remove_task_from_execute_queue( | |
1211 | 1211 | struct se_task *task, |
1212 | 1212 | struct se_device *dev) |
1213 | 1213 | { |
... | ... | @@ -5549,7 +5549,8 @@ |
5549 | 5549 | |
5550 | 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 | 5554 | goto remove; |
5554 | 5555 | |
5555 | 5556 | atomic_set(&T_TASK(cmd)->t_transport_stop, 1); |
... | ... | @@ -5956,6 +5957,9 @@ |
5956 | 5957 | |
5957 | 5958 | atomic_set(&task->task_active, 0); |
5958 | 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 | 5964 | __transport_stop_task_timer(task, &flags); |
5961 | 5965 |
include/target/target_core_transport.h
... | ... | @@ -135,6 +135,8 @@ |
135 | 135 | extern void transport_add_task_to_execute_queue(struct se_task *, |
136 | 136 | struct se_task *, |
137 | 137 | struct se_device *); |
138 | +extern void transport_remove_task_from_execute_queue(struct se_task *, | |
139 | + struct se_device *); | |
138 | 140 | unsigned char *transport_dump_cmd_direction(struct se_cmd *); |
139 | 141 | extern void transport_dump_dev_state(struct se_device *, char *, int *); |
140 | 142 | extern void transport_dump_dev_info(struct se_device *, struct se_lun *, |