From fab0164c55639b03ce5fdded20041138182b8b41 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 23 Oct 2012 01:08:47 +0000 Subject: [PATCH] scst_local: Avoid deadlock during module removal with kernel 3.6 Since kernel 3.6 a SYNCHRONIZE CACHE command is sent to SCSI disks during the scsi_remove_host() call. That command is sent after command processing has been suspended in SCST and hence causes a deadlock. Avoid this deadlock by failing all commands issued after scst_unregister_target() has been invoked. The output of echo w >/proc/sysrq-trigger just after module removal of scst_local started is as follows: SysRq : Show Blocked State task PC stack pid father kworker/2:1 D ffff88003d08cf40 0 37 2 0x00000000 ffff88003d0bd830 0000000000000046 ffffffff814a849e ffff88003d08cf40 ffff88003d08cf40 ffff88003d0bdfd8 ffff88003d0bdfd8 ffff88003d0bdfd8 ffff88003d9a3b70 ffff88003d08cf40 0000000000000282 ffff88003d0bd860 Call Trace: [] ? schedule_timeout+0x12e/0x230 [] schedule+0x29/0x70 [] schedule_timeout+0x133/0x230 [] ? __internal_add_timer+0x140/0x140 [] wait_for_common+0x122/0x170 [] ? try_to_wake_up+0x2c0/0x2c0 [] wait_for_completion_timeout+0x13/0x20 [] blk_execute_rq+0x17b/0x200 [] ? wait_for_common+0x43/0x170 [] ? bio_phys_segments+0x21/0x30 [] ? blk_rq_bio_prep+0x30/0xb0 [] scsi_execute+0xee/0x180 [] scsi_execute_req+0xbd/0x130 [] sr_check_events+0xc0/0x2d0 [] ? sched_clock_cpu+0xa8/0x110 [] cdrom_check_events+0x1c/0x40 [] sr_block_check_events+0x19/0x20 [] disk_events_workfn+0x62/0x160 [] process_one_work+0x1ae/0x620 [] ? process_one_work+0x14d/0x620 [] ? __disk_unblock_events+0x130/0x130 [] worker_thread+0x187/0x4e0 [] ? manage_workers+0x320/0x320 [] kthread+0xb7/0xc0 [] ? trace_hardirqs_on_caller+0x105/0x190 [] kernel_thread_helper+0x4/0x10 [] ? retint_restore_args+0x13/0x13 [] ? flush_kthread_work+0x1e0/0x1e0 [] ? gs_change+0x13/0x13 rmmod D ffff88001d46a7a0 0 10456 10437 0x00000004 ffff8800393cd7a8 0000000000000046 ffffffff814a849e ffff88001d46a7a0 ffff88001d46a7a0 ffff8800393cdfd8 ffff8800393cdfd8 ffff8800393cdfd8 ffffffff81a13420 ffff88001d46a7a0 0000000000000282 ffff8800393cd7d8 Call Trace: [] ? schedule_timeout+0x12e/0x230 [] schedule+0x29/0x70 [] schedule_timeout+0x133/0x230 [] ? __internal_add_timer+0x140/0x140 [] wait_for_common+0x122/0x170 [] ? try_to_wake_up+0x2c0/0x2c0 [] wait_for_completion_timeout+0x13/0x20 [] blk_execute_rq+0x17b/0x200 [] ? wait_for_common+0x43/0x170 [] ? __init_waitqueue_head+0x60/0x60 [] scsi_execute+0xee/0x180 [] scsi_execute_req+0xbd/0x130 [] sd_sync_cache+0x98/0x120 [] sd_shutdown+0xd0/0x150 [] sd_remove+0x7c/0xc0 [] __device_release_driver+0x7c/0xf0 [] device_release_driver+0x2e/0x40 [] bus_remove_device+0xff/0x170 [] device_del+0x12d/0x1c0 [] __scsi_remove_device+0x10d/0x120 [] scsi_forget_host+0x6f/0x80 [] scsi_remove_host+0x7a/0x130 [] scst_local_driver_remove+0x5a/0x120 [scst_local] [] __device_release_driver+0x7c/0xf0 [] device_release_driver+0x2e/0x40 [] bus_remove_device+0xff/0x170 [] device_del+0x12d/0x1c0 [] ? scst_local_exit+0x6b/0x24a [scst_local] [] device_unregister+0x22/0x60 [] scst_local_remove_adapter+0x59/0xd0 [scst_local] [] __scst_local_remove_target+0x7b/0x130 [scst_local] [] scst_local_exit+0x84/0x24a [scst_local] [] sys_delete_module+0x1a6/0x2b0 [] ? retint_swapgs+0x13/0x1b [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b Signed-off-by: Bart Van Assche git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4566 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst_local/scst_local.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index d84e1e636..f0ae3cb87 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -953,6 +953,12 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt, sess = to_scst_lcl_sess(scsi_get_device(SCpnt->device->host)); + if (sess->unregistering) { + SCpnt->result = DID_BAD_TARGET << 16; + SCpnt->scsi_done(SCpnt); + return 0; + } + scsi_set_resid(SCpnt, 0); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) @@ -1576,7 +1582,7 @@ static void scst_local_release_adapter(struct device *dev) goto out; spin_lock(&sess->aen_lock); - sess->unregistering = 1; + WARN_ON_ONCE(!sess->unregistering); scst_process_aens(sess, true); spin_unlock(&sess->aen_lock); @@ -1766,6 +1772,10 @@ static void __scst_local_remove_target(struct scst_local_tgt *tgt) list_for_each_entry_safe(sess, ts, &tgt->sessions_list, sessions_list_entry) { + spin_lock(&sess->aen_lock); + sess->unregistering = 1; + spin_unlock(&sess->aen_lock); + scst_local_remove_adapter(sess); }