Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Sat, 2017-03-18 at 12:17 +0100, Hannes Reinecke wrote: > On 03/17/2017 12:00 AM, Bart Van Assche wrote: > > I hadn't seen this crash before kernel v4.11-rc1 but with kernel v4.11-rc1 > > and later I see it if I let the srp-test scripts run for a few minutes. The > > patch I used to disable async aborts on my test setup is as follows: > > Thing is, I didn't change anything in the async abort case; all my > patches haven't been merged yet. > So I would rather think this being the side effect of something else > > And I just noticed that you found the real issue with your alua fixes, > so I guess this can be ignored, right? Yes - sorry for the noise. This crash did not occur with the ALUA fixes applied and async aborts enabled. Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On 03/17/2017 12:00 AM, Bart Van Assche wrote: > On Mon, 2017-03-13 at 14:55 -0700, James Bottomley wrote: >> On Mon, 2017-03-13 at 20:33 +, Bart Van Assche wrote: >>> On Mon, 2017-03-13 at 12:23 -0700, James Bottomley wrote: On Mon, 2017-03-13 at 18:49 +, Bart Van Assche wrote: > diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c > index 7bfbcfa7af40..b3bb49d06943 100644 > --- a/drivers/scsi/scsi.c > +++ b/drivers/scsi/scsi.c > @@ -602,7 +602,7 @@ EXPORT_SYMBOL(scsi_device_get); > */ > void scsi_device_put(struct scsi_device *sdev) > { > - module_put(sdev->host->hostt->module); > + module_put(sdev->hostt->module); > put_device(>sdev_gendev); > } > EXPORT_SYMBOL(scsi_device_put); > diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c > index 6f7128f49c30..7134487abbb1 100644 > --- a/drivers/scsi/scsi_scan.c > +++ b/drivers/scsi/scsi_scan.c > @@ -227,6 +227,7 @@ static struct scsi_device > *scsi_alloc_sdev(struct > scsi_target *starget, > sdev->model = scsi_null_device_strs; > sdev->rev = scsi_null_device_strs; > sdev->host = shost; > + sdev->hostt = shost->hostt; > sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; > sdev->id = starget->id; > sdev->lun = lun; > diff --git a/include/scsi/scsi_device.h > b/include/scsi/scsi_device.h > index 6f22b39f1b0c..cda620ed5922 100644 > --- a/include/scsi/scsi_device.h > +++ b/include/scsi/scsi_device.h > @@ -82,6 +82,7 @@ struct scsi_event { > > struct scsi_device { > struct Scsi_Host *host; > + struct scsi_host_template *hostt; > struct request_queue *request_queue; > The apparent assumption behind this patch is that sdev->host can be freed but the sdev will still exist? That shouldn't be correct: the rule for struct devices is that the child always holds the parent and the host is parented (albeit not necessarily directly) to the sdev, so it looks like something has gone wrong if the host had been freed before the sdev. >>> >>> Hello James, >>> >>> scsi_remove_host() decreases the sdev reference count but does not >>> wait until the sdev release work has finished. This is why the SCSI >>> host can already have disappeared before the last scsi_device_put() >>> call occurs. >> >> This is true, but I don't see how it can cause the host to be freed >> before the sdev. The memory for struct Scsi_Host is freed in the >> shost_gendev release routine, which should be pinned by the parent >> traversal from sdev. So it should not be possible for >> scsi_host_dev_release() to be called before >> scsi_device_dev_release_usercontext() becase the latter has the final >> put of the parent device. > > Hello Hannes, > > The following crash only occurs with async aborts enabled: > > general protection fault: [#1] SMP > RIP: 0010:scsi_device_put+0xb/0x30 > Call Trace: > scsi_disk_put+0x2d/0x40 > sd_release+0x3d/0xb0 > __blkdev_put+0x29e/0x360 > blkdev_put+0x49/0x170 > dm_put_table_device+0x58/0xc0 [dm_mod] > dm_put_device+0x70/0xc0 [dm_mod] > free_priority_group+0x92/0xc0 [dm_multipath] > free_multipath+0x70/0xc0 [dm_multipath] > multipath_dtr+0x19/0x20 [dm_multipath] > dm_table_destroy+0x67/0x120 [dm_mod] > dev_suspend+0xde/0x240 [dm_mod] > ctl_ioctl+0x1f5/0x520 [dm_mod] > dm_ctl_ioctl+0xe/0x20 [dm_mod] > do_vfs_ioctl+0x8f/0x700 > SyS_ioctl+0x3c/0x70 > entry_SYSCALL_64_fastpath+0x18/0xad > > I hadn't seen this crash before kernel v4.11-rc1 but with kernel v4.11-rc1 > and later I see it if I let the srp-test scripts run for a few minutes. The > patch I used to disable async aborts on my test setup is as follows: > How utterly curious. Thing is, I didn't change anything in the async abort case; all my patches haven't been merged yet. So I would rather think this being the side effect of something else And I just noticed that you found the real issue with your alua fixes, so I guess this can be ignored, right? Cheers, Hannes -- Dr. Hannes Reinecke zSeries & Storage h...@suse.de +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Thu, 2017-03-16 at 23:00 +, Bart Van Assche wrote: > The following crash only occurs with async aborts enabled: > > general protection fault: [#1] SMP > RIP: 0010:scsi_device_put+0xb/0x30 > Call Trace: > scsi_disk_put+0x2d/0x40 > sd_release+0x3d/0xb0 > __blkdev_put+0x29e/0x360 > blkdev_put+0x49/0x170 > dm_put_table_device+0x58/0xc0 [dm_mod] > dm_put_device+0x70/0xc0 [dm_mod] > free_priority_group+0x92/0xc0 [dm_multipath] > free_multipath+0x70/0xc0 [dm_multipath] > multipath_dtr+0x19/0x20 [dm_multipath] > dm_table_destroy+0x67/0x120 [dm_mod] > dev_suspend+0xde/0x240 [dm_mod] > ctl_ioctl+0x1f5/0x520 [dm_mod] > dm_ctl_ioctl+0xe/0x20 [dm_mod] > do_vfs_ioctl+0x8f/0x700 > SyS_ioctl+0x3c/0x70 > entry_SYSCALL_64_fastpath+0x18/0xad (replying to my own e-mail) With my three scsi_dh_alua patches applied I don't see this crash anymore so this crash was probably unrelated to async aborts. Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Mon, 2017-03-13 at 14:55 -0700, James Bottomley wrote: > On Mon, 2017-03-13 at 20:33 +, Bart Van Assche wrote: > > On Mon, 2017-03-13 at 12:23 -0700, James Bottomley wrote: > > > On Mon, 2017-03-13 at 18:49 +, Bart Van Assche wrote: > > > > diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c > > > > index 7bfbcfa7af40..b3bb49d06943 100644 > > > > --- a/drivers/scsi/scsi.c > > > > +++ b/drivers/scsi/scsi.c > > > > @@ -602,7 +602,7 @@ EXPORT_SYMBOL(scsi_device_get); > > > > */ > > > > void scsi_device_put(struct scsi_device *sdev) > > > > { > > > > - module_put(sdev->host->hostt->module); > > > > + module_put(sdev->hostt->module); > > > > put_device(>sdev_gendev); > > > > } > > > > EXPORT_SYMBOL(scsi_device_put); > > > > diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c > > > > index 6f7128f49c30..7134487abbb1 100644 > > > > --- a/drivers/scsi/scsi_scan.c > > > > +++ b/drivers/scsi/scsi_scan.c > > > > @@ -227,6 +227,7 @@ static struct scsi_device > > > > *scsi_alloc_sdev(struct > > > > scsi_target *starget, > > > > sdev->model = scsi_null_device_strs; > > > > sdev->rev = scsi_null_device_strs; > > > > sdev->host = shost; > > > > + sdev->hostt = shost->hostt; > > > > sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; > > > > sdev->id = starget->id; > > > > sdev->lun = lun; > > > > diff --git a/include/scsi/scsi_device.h > > > > b/include/scsi/scsi_device.h > > > > index 6f22b39f1b0c..cda620ed5922 100644 > > > > --- a/include/scsi/scsi_device.h > > > > +++ b/include/scsi/scsi_device.h > > > > @@ -82,6 +82,7 @@ struct scsi_event { > > > > > > > > struct scsi_device { > > > > struct Scsi_Host *host; > > > > + struct scsi_host_template *hostt; > > > > struct request_queue *request_queue; > > > > > > > > > > The apparent assumption behind this patch is that sdev->host can be > > > freed but the sdev will still exist? That shouldn't be correct: > > > the > > > rule for struct devices is that the child always holds the parent > > > and > > > the host is parented (albeit not necessarily directly) to the sdev, > > > so > > > it looks like something has gone wrong if the host had been freed > > > before the sdev. > > > > Hello James, > > > > scsi_remove_host() decreases the sdev reference count but does not > > wait until the sdev release work has finished. This is why the SCSI > > host can already have disappeared before the last scsi_device_put() > > call occurs. > > This is true, but I don't see how it can cause the host to be freed > before the sdev. The memory for struct Scsi_Host is freed in the > shost_gendev release routine, which should be pinned by the parent > traversal from sdev. So it should not be possible for > scsi_host_dev_release() to be called before > scsi_device_dev_release_usercontext() becase the latter has the final > put of the parent device. Hello Hannes, The following crash only occurs with async aborts enabled: general protection fault: [#1] SMP RIP: 0010:scsi_device_put+0xb/0x30 Call Trace: scsi_disk_put+0x2d/0x40 sd_release+0x3d/0xb0 __blkdev_put+0x29e/0x360 blkdev_put+0x49/0x170 dm_put_table_device+0x58/0xc0 [dm_mod] dm_put_device+0x70/0xc0 [dm_mod] free_priority_group+0x92/0xc0 [dm_multipath] free_multipath+0x70/0xc0 [dm_multipath] multipath_dtr+0x19/0x20 [dm_multipath] dm_table_destroy+0x67/0x120 [dm_mod] dev_suspend+0xde/0x240 [dm_mod] ctl_ioctl+0x1f5/0x520 [dm_mod] dm_ctl_ioctl+0xe/0x20 [dm_mod] do_vfs_ioctl+0x8f/0x700 SyS_ioctl+0x3c/0x70 entry_SYSCALL_64_fastpath+0x18/0xad I hadn't seen this crash before kernel v4.11-rc1 but with kernel v4.11-rc1 and later I see it if I let the srp-test scripts run for a few minutes. The patch I used to disable async aborts on my test setup is as follows: diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f2cafae150bc..9075e126d6c8 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -171,6 +171,7 @@ scmd_eh_abort_handler(struct work_struct *work) } } +#if 0 /** * scsi_abort_command - schedule a command abort * @scmd: scmd to abort. @@ -219,6 +220,12 @@ scsi_abort_command(struct scsi_cmnd *scmd) queue_delayed_work(shost->tmf_work_q, >abort_work, HZ / 100); return SUCCESS; } +#else +static int scsi_abort_command(struct scsi_cmnd *scmd) +{ + return FAILED; +} +#endif /** * scsi_eh_scmd_add - add scsi cmd to error handling. Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On 3/16/2017 5:42 PM, Bart Van Assche wrote: On Thu, 2017-03-16 at 11:02 +0200, Israel Rukshin wrote: I tested your patches and the hang disappeared when fast_io_fail_tmo expired. The warning from patch 1 still exist, so we need an additional fix for that. Hello Israel, Thanks for the testing! I will leave out patch 1 for now since it is not needed to fix the hang. I assume that your e-mail counts as a Tested-by? PS: please do not top-post when replying. This is considered annoying in the Linux kernel community. Bart. Hello Bart, Yes, you can add me as Tested-by. Israel.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Thu, 2017-03-16 at 11:02 +0200, Israel Rukshin wrote: > I tested your patches and the hang disappeared when fast_io_fail_tmo > expired. The warning from patch 1 still exist, so we need an additional > fix for that. Hello Israel, Thanks for the testing! I will leave out patch 1 for now since it is not needed to fix the hang. I assume that your e-mail counts as a Tested-by? PS: please do not top-post when replying. This is considered annoying in the Linux kernel community. Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
Hi Bart, I tested your patches and the hang disappeared when fast_io_fail_tmo expired. The warning from patch 1 still exist, so we need an additional fix for that. Regards, Israel On 3/16/2017 1:27 AM, Bart Van Assche wrote: On Tue, 2017-03-14 at 16:23 +0200, Israel Rukshin wrote: Patch number 5 doesn't handle the case when device_for_each_child() is called. device_for_each_child() calls to target_unblock() that uses also starget_for_each_device(). After applying also the following change the hang disappeared but it didn't fix the warning. Those fixes are not enough because if fast_io_fail_tmo is set to infinity then the hang will remain, because only __rport_fail_io_fast() calls to scsi_target_unblock() and terminate_rport_io() that free the sync cache command. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e5d4b50..09f9566 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3068,9 +3068,15 @@ void scsi_device_resume(struct scsi_device *sdev) static int target_unblock(struct device *dev, void *data) { - if (scsi_is_target_device(dev)) - starget_for_each_device(to_scsi_target(dev), data, - device_unblock); + if (scsi_is_target_device(dev)) { + struct scsi_target *starget = to_scsi_target(dev); + struct Scsi_Host *shost = dev_to_shost(dev->parent); + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + __starget_for_each_device(starget, data, device_unblock); + spin_unlock_irqrestore(shost->host_lock, flags); + } return 0; } Hello Israel, Regarding setting fast_io_fail_tmo to infinity: that does not prevent kernel module unloading because srp_timed_out() stops resetting the timer as soon as the SCSI device is unblocked. The above patch should realize that but suffers from the same issue as a patch attached to my previous e-mail, namely lock inversion. For at least the following call chain the block layer queue lock is the outer lock and the SCSI host lock is the inner lock: ata_qc_schedule_eh() -> blk_abort_request() -> blk_mq_rq_timed_out() -> scsi_timeout() -> scsi_times_out() -> scsi_eh_scmd_add() So I think we should avoid introducing code with the SCSI host lock as outer lock and the block layer queue lock as inner lock. How about the attached four patches? Thanks, Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Tue, 2017-03-14 at 16:23 +0200, Israel Rukshin wrote: > Patch number 5 doesn't handle the case when device_for_each_child() is > called. device_for_each_child() calls to target_unblock() that uses also > starget_for_each_device(). After applying also the following change the > hang disappeared but it didn't fix the warning. Those fixes are not enough > because if fast_io_fail_tmo is set to infinity then the hang will remain, > because only __rport_fail_io_fast() calls to scsi_target_unblock() and > terminate_rport_io() that free the sync cache command. > > diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c > index e5d4b50..09f9566 100644 > --- a/drivers/scsi/scsi_lib.c > +++ b/drivers/scsi/scsi_lib.c > @@ -3068,9 +3068,15 @@ void scsi_device_resume(struct scsi_device *sdev) > static int > target_unblock(struct device *dev, void *data) > { > - if (scsi_is_target_device(dev)) > - starget_for_each_device(to_scsi_target(dev), data, > - device_unblock); > + if (scsi_is_target_device(dev)) { > + struct scsi_target *starget = to_scsi_target(dev); > + struct Scsi_Host *shost = dev_to_shost(dev->parent); > + unsigned long flags; > + > + spin_lock_irqsave(shost->host_lock, flags); > + __starget_for_each_device(starget, data, device_unblock); > + spin_unlock_irqrestore(shost->host_lock, flags); > + } > return 0; > } Hello Israel, Regarding setting fast_io_fail_tmo to infinity: that does not prevent kernel module unloading because srp_timed_out() stops resetting the timer as soon as the SCSI device is unblocked. The above patch should realize that but suffers from the same issue as a patch attached to my previous e-mail, namely lock inversion. For at least the following call chain the block layer queue lock is the outer lock and the SCSI host lock is the inner lock: ata_qc_schedule_eh() -> blk_abort_request() -> blk_mq_rq_timed_out() -> scsi_timeout() -> scsi_times_out() -> scsi_eh_scmd_add() So I think we should avoid introducing code with the SCSI host lock as outer lock and the block layer queue lock as inner lock. How about the attached four patches? Thanks, Bart.From 458959938476788710738039a7c195e9c48ff338 Mon Sep 17 00:00:00 2001 From: Bart Van AsscheDate: Mon, 13 Mar 2017 10:06:13 -0700 Subject: [PATCH 1/4] Warn if __scsi_remove_device() is called for a stopped queue Calling __scsi_remove_device() for a stopped queue is a bug because the device_del() call can trigger I/O and will trigger e.g. the following hang: Call Trace: [] schedule+0x35/0x80 [] schedule_timeout+0x237/0x2d0 [] io_schedule_timeout+0xa6/0x110 [] wait_for_completion_io+0xa3/0x110 [] blk_execute_rq+0xdf/0x120 [] scsi_execute+0xce/0x150 [scsi_mod] [] scsi_execute_req_flags+0x8f/0xf0 [scsi_mod] [] sd_sync_cache+0xa9/0x190 [sd_mod] [] sd_shutdown+0x6a/0x100 [sd_mod] [] sd_remove+0x64/0xc0 [sd_mod] [] __device_release_driver+0x8d/0x120 [] device_release_driver+0x1e/0x30 [] bus_remove_device+0xf9/0x170 [] device_del+0x127/0x240 [] __scsi_remove_device+0xc1/0xd0 [scsi_mod] [] scsi_forget_host+0x57/0x60 [scsi_mod] [] scsi_remove_host+0x72/0x110 [scsi_mod] [] srp_remove_work+0x8b/0x200 [ib_srp] Reported-by: Israel Rukshin Signed-off-by: Bart Van Assche --- drivers/scsi/scsi_sysfs.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 82dfe07b1d47..bbe7efd144b2 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1274,6 +1274,12 @@ void __scsi_remove_device(struct scsi_device *sdev) struct device *dev = >sdev_gendev; /* + * Calling __scsi_remove_device() for a stopped queue is a bug because + * the device_del() call can trigger I/O. See also sd_remove(). + */ + WARN_ON_ONCE(blk_queue_stopped(sdev->request_queue)); + + /* * This cleanup path is not reentrant and while it is impossible * to get a new reference with scsi_device_get() someone can still * hold a previously acquired one. -- 2.12.0 From b86b5087698c73f5fdd8cc9fa18ed3f1e9e174bb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Mar 2017 15:12:43 -0700 Subject: [PATCH 2/4] __scsi_iterate_devices(): Make the get and put functions arguments This patch does not change any functionality. Signed-off-by: Bart Van Assche Cc: --- drivers/scsi/scsi.c| 8 +--- include/scsi/scsi_device.h | 16 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b3bb49d06943..45c266009f20 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -609,7 +609,9 @@ EXPORT_SYMBOL(scsi_device_put); /* helper for shost_for_each_device,
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
Hello Bart, Patch number 5 doesn't handle the case when device_for_each_child() is called. device_for_each_child() calls to target_unblock() that uses also starget_for_each_device(). After applying also the following change the hang disappeared but it didn't fix the warning. Those fixes are not enough because if fast_io_fail_tmo is set to infinity then the hang will remain, because only __rport_fail_io_fast() calls to scsi_target_unblock() and terminate_rport_io() that free the sync cache command. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e5d4b50..09f9566 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3068,9 +3068,15 @@ void scsi_device_resume(struct scsi_device *sdev) static int target_unblock(struct device *dev, void *data) { - if (scsi_is_target_device(dev)) - starget_for_each_device(to_scsi_target(dev), data, - device_unblock); + if (scsi_is_target_device(dev)) { + struct scsi_target *starget = to_scsi_target(dev); + struct Scsi_Host *shost = dev_to_shost(dev->parent); + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + __starget_for_each_device(starget, data, device_unblock); + spin_unlock_irqrestore(shost->host_lock, flags); + } return 0; } -- 1.8.4.3 Israel On 3/14/2017 11:44 AM, Israel Rukshin wrote: Hello Bart, I applied and tested patches 3, 4 and 5. I am sorry to tell you that it didn't work. I saw the warning you added and the hang at device_del(). [ 333.696462] [ cut here ] [ 333.696471] WARNING: CPU: 11 PID: 321 at drivers/scsi/scsi_sysfs.c:1280 __scsi_remove_device+0x106/0x110 [ 333.696472] Modules linked in: nfsv3 ib_srp(-) dm_service_time scsi_transport_srp ib_uverbs ib_umad ib_ipoib ib_cm mlx4_ib ib_core rpcsec_gss_krb5 nfsv4 dns_resolver nfs netconsole fscache dm_mirror dm_region_hash dm_log sb_edac edac_core x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel iTCO_wdt pcbc iTCO_vendor_support aesni_intel mei_me crypto_simd joydev input_leds ipmi_si ioatdma mei glue_helper lpc_ich pcspkr cryptd ipmi_devintf shpchp ipmi_msghandler sg i2c_i801 mfd_core dm_multipath dm_mod nfsd binfmt_misc auth_rpcgss nfs_acl lockd grace sunrpc ip_tables ext4 jbd2 mbcache sd_mod mgag200 drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops isci igb ttm ahci libsas ptp libahci scsi_transport_sas pps_core dca crc32c_intel [ 333.696511] drm i2c_algo_bit libata mlx4_core fjes [last unloaded: ib_srp] [ 333.696516] CPU: 11 PID: 321 Comm: kworker/11:1 Not tainted 4.11.0-rc2+ #99 [ 333.696517] Hardware name: Supermicro X9DRFR/X9DRFR, BIOS 1.0a 09/11/2012 [ 333.696522] Workqueue: srp_remove srp_remove_work [ib_srp] [ 333.696523] Call Trace: [ 333.696530] dump_stack+0x63/0x90 [ 333.696534] __warn+0xcb/0xf0 [ 333.696536] warn_slowpath_null+0x1d/0x20 [ 333.696538] __scsi_remove_device+0x106/0x110 [ 333.696540] scsi_forget_host+0x60/0x70 [ 333.696545] scsi_remove_host+0x77/0x110 [ 333.696547] srp_remove_work+0x90/0x230 [ib_srp] [ 333.696551] process_one_work+0x177/0x430 [ 333.696553] worker_thread+0x4e/0x4b0 [ 333.696555] kthread+0x101/0x140 [ 333.696556] ? process_one_work+0x430/0x430 [ 333.696558] ? kthread_create_on_node+0x60/0x60 [ 333.696563] ret_from_fork+0x2c/0x40 [ 333.696565] ---[ end trace b1edd584bf21aaba ]--- Israel. On 3/14/2017 4:35 AM, Bart Van Assche wrote: On Mon, 2017-03-13 at 14:55 -0700, James Bottomley wrote: This is true, but I don't see how it can cause the host to be freed before the sdev. The memory for struct Scsi_Host is freed in the shost_gendev release routine, which should be pinned by the parent traversal from sdev. So it should not be possible for scsi_host_dev_release() to be called before scsi_device_dev_release_usercontext() becase the latter has the final put of the parent device. Hello James, I will run a bisect to see whether that provides more information about what caused the change in the reference counting behavior. Israel, since you did not hit the reference counting issue in your tests, can you repeat your test with patches 3, 4 and 5 applied? Thanks, Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
Hello Bart, I applied and tested patches 3, 4 and 5. I am sorry to tell you that it didn't work. I saw the warning you added and the hang at device_del(). [ 333.696462] [ cut here ] [ 333.696471] WARNING: CPU: 11 PID: 321 at drivers/scsi/scsi_sysfs.c:1280 __scsi_remove_device+0x106/0x110 [ 333.696472] Modules linked in: nfsv3 ib_srp(-) dm_service_time scsi_transport_srp ib_uverbs ib_umad ib_ipoib ib_cm mlx4_ib ib_core rpcsec_gss_krb5 nfsv4 dns_resolver nfs netconsole fscache dm_mirror dm_region_hash dm_log sb_edac edac_core x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel iTCO_wdt pcbc iTCO_vendor_support aesni_intel mei_me crypto_simd joydev input_leds ipmi_si ioatdma mei glue_helper lpc_ich pcspkr cryptd ipmi_devintf shpchp ipmi_msghandler sg i2c_i801 mfd_core dm_multipath dm_mod nfsd binfmt_misc auth_rpcgss nfs_acl lockd grace sunrpc ip_tables ext4 jbd2 mbcache sd_mod mgag200 drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops isci igb ttm ahci libsas ptp libahci scsi_transport_sas pps_core dca crc32c_intel [ 333.696511] drm i2c_algo_bit libata mlx4_core fjes [last unloaded: ib_srp] [ 333.696516] CPU: 11 PID: 321 Comm: kworker/11:1 Not tainted 4.11.0-rc2+ #99 [ 333.696517] Hardware name: Supermicro X9DRFR/X9DRFR, BIOS 1.0a 09/11/2012 [ 333.696522] Workqueue: srp_remove srp_remove_work [ib_srp] [ 333.696523] Call Trace: [ 333.696530] dump_stack+0x63/0x90 [ 333.696534] __warn+0xcb/0xf0 [ 333.696536] warn_slowpath_null+0x1d/0x20 [ 333.696538] __scsi_remove_device+0x106/0x110 [ 333.696540] scsi_forget_host+0x60/0x70 [ 333.696545] scsi_remove_host+0x77/0x110 [ 333.696547] srp_remove_work+0x90/0x230 [ib_srp] [ 333.696551] process_one_work+0x177/0x430 [ 333.696553] worker_thread+0x4e/0x4b0 [ 333.696555] kthread+0x101/0x140 [ 333.696556] ? process_one_work+0x430/0x430 [ 333.696558] ? kthread_create_on_node+0x60/0x60 [ 333.696563] ret_from_fork+0x2c/0x40 [ 333.696565] ---[ end trace b1edd584bf21aaba ]--- Israel. On 3/14/2017 4:35 AM, Bart Van Assche wrote: On Mon, 2017-03-13 at 14:55 -0700, James Bottomley wrote: This is true, but I don't see how it can cause the host to be freed before the sdev. The memory for struct Scsi_Host is freed in the shost_gendev release routine, which should be pinned by the parent traversal from sdev. So it should not be possible for scsi_host_dev_release() to be called before scsi_device_dev_release_usercontext() becase the latter has the final put of the parent device. Hello James, I will run a bisect to see whether that provides more information about what caused the change in the reference counting behavior. Israel, since you did not hit the reference counting issue in your tests, can you repeat your test with patches 3, 4 and 5 applied? Thanks, Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Mon, 2017-03-13 at 14:55 -0700, James Bottomley wrote: > This is true, but I don't see how it can cause the host to be freed > before the sdev. The memory for struct Scsi_Host is freed in the > shost_gendev release routine, which should be pinned by the parent > traversal from sdev. So it should not be possible for > scsi_host_dev_release() to be called before > scsi_device_dev_release_usercontext() becase the latter has the final > put of the parent device. Hello James, I will run a bisect to see whether that provides more information about what caused the change in the reference counting behavior. Israel, since you did not hit the reference counting issue in your tests, can you repeat your test with patches 3, 4 and 5 applied? Thanks, Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Mon, 2017-03-13 at 20:33 +, Bart Van Assche wrote: > On Mon, 2017-03-13 at 12:23 -0700, James Bottomley wrote: > > On Mon, 2017-03-13 at 18:49 +, Bart Van Assche wrote: > > > diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c > > > index 7bfbcfa7af40..b3bb49d06943 100644 > > > --- a/drivers/scsi/scsi.c > > > +++ b/drivers/scsi/scsi.c > > > @@ -602,7 +602,7 @@ EXPORT_SYMBOL(scsi_device_get); > > > */ > > > void scsi_device_put(struct scsi_device *sdev) > > > { > > > - module_put(sdev->host->hostt->module); > > > + module_put(sdev->hostt->module); > > > put_device(>sdev_gendev); > > > } > > > EXPORT_SYMBOL(scsi_device_put); > > > diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c > > > index 6f7128f49c30..7134487abbb1 100644 > > > --- a/drivers/scsi/scsi_scan.c > > > +++ b/drivers/scsi/scsi_scan.c > > > @@ -227,6 +227,7 @@ static struct scsi_device > > > *scsi_alloc_sdev(struct > > > scsi_target *starget, > > > sdev->model = scsi_null_device_strs; > > > sdev->rev = scsi_null_device_strs; > > > sdev->host = shost; > > > + sdev->hostt = shost->hostt; > > > sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; > > > sdev->id = starget->id; > > > sdev->lun = lun; > > > diff --git a/include/scsi/scsi_device.h > > > b/include/scsi/scsi_device.h > > > index 6f22b39f1b0c..cda620ed5922 100644 > > > --- a/include/scsi/scsi_device.h > > > +++ b/include/scsi/scsi_device.h > > > @@ -82,6 +82,7 @@ struct scsi_event { > > > > > > struct scsi_device { > > > struct Scsi_Host *host; > > > + struct scsi_host_template *hostt; > > > struct request_queue *request_queue; > > > > > > > The apparent assumption behind this patch is that sdev->host can be > > freed but the sdev will still exist? That shouldn't be correct: > > the > > rule for struct devices is that the child always holds the parent > > and > > the host is parented (albeit not necessarily directly) to the sdev, > > so > > it looks like something has gone wrong if the host had been freed > > before the sdev. > > Hello James, > > scsi_remove_host() decreases the sdev reference count but does not > wait until the sdev release work has finished. This is why the SCSI > host can already have disappeared before the last scsi_device_put() > call occurs. This is true, but I don't see how it can cause the host to be freed before the sdev. The memory for struct Scsi_Host is freed in the shost_gendev release routine, which should be pinned by the parent traversal from sdev. So it should not be possible for scsi_host_dev_release() to be called before scsi_device_dev_release_usercontext() becase the latter has the final put of the parent device. James
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Mon, 2017-03-13 at 12:23 -0700, James Bottomley wrote: > On Mon, 2017-03-13 at 18:49 +, Bart Van Assche wrote: > > diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c > > index 7bfbcfa7af40..b3bb49d06943 100644 > > --- a/drivers/scsi/scsi.c > > +++ b/drivers/scsi/scsi.c > > @@ -602,7 +602,7 @@ EXPORT_SYMBOL(scsi_device_get); > > */ > > void scsi_device_put(struct scsi_device *sdev) > > { > > - module_put(sdev->host->hostt->module); > > + module_put(sdev->hostt->module); > > put_device(>sdev_gendev); > > } > > EXPORT_SYMBOL(scsi_device_put); > > diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c > > index 6f7128f49c30..7134487abbb1 100644 > > --- a/drivers/scsi/scsi_scan.c > > +++ b/drivers/scsi/scsi_scan.c > > @@ -227,6 +227,7 @@ static struct scsi_device *scsi_alloc_sdev(struct > > scsi_target *starget, > > sdev->model = scsi_null_device_strs; > > sdev->rev = scsi_null_device_strs; > > sdev->host = shost; > > + sdev->hostt = shost->hostt; > > sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; > > sdev->id = starget->id; > > sdev->lun = lun; > > diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h > > index 6f22b39f1b0c..cda620ed5922 100644 > > --- a/include/scsi/scsi_device.h > > +++ b/include/scsi/scsi_device.h > > @@ -82,6 +82,7 @@ struct scsi_event { > > > > struct scsi_device { > > struct Scsi_Host *host; > > + struct scsi_host_template *hostt; > > struct request_queue *request_queue; > > > > The apparent assumption behind this patch is that sdev->host can be > freed but the sdev will still exist? That shouldn't be correct: the > rule for struct devices is that the child always holds the parent and > the host is parented (albeit not necessarily directly) to the sdev, so > it looks like something has gone wrong if the host had been freed > before the sdev. Hello James, scsi_remove_host() decreases the sdev reference count but does not wait until the sdev release work has finished. This is why the SCSI host can already have disappeared before the last scsi_device_put() call occurs. Bart.
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Mon, 2017-03-13 at 18:49 +, Bart Van Assche wrote: > diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c > index 7bfbcfa7af40..b3bb49d06943 100644 > --- a/drivers/scsi/scsi.c > +++ b/drivers/scsi/scsi.c > @@ -602,7 +602,7 @@ EXPORT_SYMBOL(scsi_device_get); > */ > void scsi_device_put(struct scsi_device *sdev) > { > - module_put(sdev->host->hostt->module); > + module_put(sdev->hostt->module); > put_device(>sdev_gendev); > } > EXPORT_SYMBOL(scsi_device_put); > diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c > index 6f7128f49c30..7134487abbb1 100644 > --- a/drivers/scsi/scsi_scan.c > +++ b/drivers/scsi/scsi_scan.c > @@ -227,6 +227,7 @@ static struct scsi_device *scsi_alloc_sdev(struct > scsi_target *starget, > sdev->model = scsi_null_device_strs; > sdev->rev = scsi_null_device_strs; > sdev->host = shost; > + sdev->hostt = shost->hostt; > sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; > sdev->id = starget->id; > sdev->lun = lun; > diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h > index 6f22b39f1b0c..cda620ed5922 100644 > --- a/include/scsi/scsi_device.h > +++ b/include/scsi/scsi_device.h > @@ -82,6 +82,7 @@ struct scsi_event { > > struct scsi_device { > struct Scsi_Host *host; > + struct scsi_host_template *hostt; > struct request_queue *request_queue; > The apparent assumption behind this patch is that sdev->host can be freed but the sdev will still exist? That shouldn't be correct: the rule for struct devices is that the child always holds the parent and the host is parented (albeit not necessarily directly) to the sdev, so it looks like something has gone wrong if the host had been freed before the sdev. James
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Sun, 2017-03-12 at 12:26 +0200, Israel Rukshin wrote: > scsi_device_get() affects I/O because scsi_target_unblock() use it and calls > to blk_start_queue(). > terminate_rport_io() is called after scsi_target_unblock() and completes all > the commands > including the SYNCHRONIZE CACHE command. > > I applied your patch and you can see that QUEUE_FLAG_STOPPED is on. Hello Israel, Thanks, that's very interesting feedback. Sorry but I prefer to fix scsi_target_unblock() instead of changing __scsi_remove_device(). Would it be possible to verify whether the five attached patches fix the issue you had reported? Thanks, Bart.From 3c5882c9cd88265ff81f6321edc3caf2a2981f55 Mon Sep 17 00:00:00 2001 From: Bart Van AsscheDate: Fri, 3 Mar 2017 11:13:39 -0800 Subject: [PATCH 1/5] Avoid that scsi_device_put() triggers a use-after-free Avoid that the following crash occurs, a crash that is easy to trigger with kernel v4.11-rc1 but that I only saw sporadically in the past: general protection fault: [#1] SMP RIP: 0010:scsi_device_put+0xb/0x30 Call Trace: scsi_disk_put+0x2d/0x40 sd_release+0x3d/0xb0 __blkdev_put+0x29e/0x360 blkdev_put+0x49/0x170 dm_put_table_device+0x58/0xc0 [dm_mod] dm_put_device+0x70/0xc0 [dm_mod] free_priority_group+0x92/0xc0 [dm_multipath] free_multipath+0x70/0xc0 [dm_multipath] multipath_dtr+0x19/0x20 [dm_multipath] dm_table_destroy+0x67/0x120 [dm_mod] dev_suspend+0xde/0x240 [dm_mod] ctl_ioctl+0x1f5/0x520 [dm_mod] dm_ctl_ioctl+0xe/0x20 [dm_mod] do_vfs_ioctl+0x8f/0x700 SyS_ioctl+0x3c/0x70 entry_SYSCALL_64_fastpath+0x18/0xad Signed-off-by: Bart Van Assche Cc: --- drivers/scsi/scsi.c| 2 +- drivers/scsi/scsi_scan.c | 1 + include/scsi/scsi_device.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 7bfbcfa7af40..b3bb49d06943 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -602,7 +602,7 @@ EXPORT_SYMBOL(scsi_device_get); */ void scsi_device_put(struct scsi_device *sdev) { - module_put(sdev->host->hostt->module); + module_put(sdev->hostt->module); put_device(>sdev_gendev); } EXPORT_SYMBOL(scsi_device_put); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6f7128f49c30..7134487abbb1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -227,6 +227,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, sdev->model = scsi_null_device_strs; sdev->rev = scsi_null_device_strs; sdev->host = shost; + sdev->hostt = shost->hostt; sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; sdev->id = starget->id; sdev->lun = lun; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 6f22b39f1b0c..cda620ed5922 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -82,6 +82,7 @@ struct scsi_event { struct scsi_device { struct Scsi_Host *host; + struct scsi_host_template *hostt; struct request_queue *request_queue; /* the next two are protected by the host->host_lock */ -- 2.12.0 From ec349df5c6b0336c746c109895d717b2be8151cb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Mar 2017 11:05:13 -0800 Subject: [PATCH 2/5] Change sdev->host->hostt into sdev->hostt Now that the host template pointer is cached in the SCSI device structure, use that pointer instead of going around through the SCSI host. This patch does not change any functionality. Signed-off-by: Bart Van Assche --- drivers/scsi/osst.c | 7 +++ drivers/scsi/raid_class.c | 2 +- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_error.c | 10 +- drivers/scsi/scsi_ioctl.c | 4 ++-- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/scsi_scan.c | 4 ++-- drivers/scsi/scsi_sysfs.c | 16 drivers/scsi/sd.c | 8 drivers/scsi/sg.c | 14 +- drivers/scsi/st.c | 5 ++--- 11 files changed, 34 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index c47f4b349bac..410a5865eae3 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5285,11 +5285,10 @@ static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned struct osst_tape *STp = file->private_data; struct scsi_device *sdev = STp->device; int ret = -ENOIOCTLCMD; - if (sdev->host->hostt->compat_ioctl) { - ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); - - } + if (sdev->hostt->compat_ioctl) + ret = sdev->hostt->compat_ioctl(sdev, cmd_in, + (void __user *)arg); return ret; } #endif diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 2c146b44d95f..ccde6e1d8dd5 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -67,7 +67,7 @@ static int raid_match(struct attribute_container *cont, struct
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
Hi Bart, scsi_device_get() affect I/O because scsi_target_unblock() use it and calls to blk_start_queue(). terminate_rport_io() is called after scsi_target_unblock() and completes all the commands including the SYNCHRONIZE CACHE command. I applied your patch and you can see that QUEUE_FLAG_STOPPED is on. [ 342.485087] sd 7:0:0:0: Device offlined - not ready after error recovery [ 342.505738] scsi host10: ib_srp: Path record query failed [ 342.512023] sd 10:0:0:0: Device offlined - not ready after error recovery [ 342.589265] sd 7:0:0:0: __scsi_remove_device: device_busy = 0 device_blocked = 0 [ 342.624110] sd 7:0:0:0: [sdc] Synchronizing SCSI cache [ 342.630263] sd 7:0:0:0: [sdc] Synchronize Cache(10) failed: Result: hostbyte=DID_TRANSPORT_FAILFAST driverbyte=DRIVER_OK [ 342.649504] scsi 7:0:0:0: alua: Detached [ 342.769099] [ cut here ] [ 342.769107] WARNING: CPU: 10 PID: 317 at drivers/scsi/scsi_sysfs.c:1293 __scsi_remove_device+0x131/0x140 [ 342.769108] Modules linked in: nfsv3 ib_srp(-) dm_service_time scsi_transport_srp ib_uverbs ib_umad ib_ipoib ib_cm mlx4_ib ib_core rpcsec_gss_krb5 nfsv4 dns_resolver nfs netconsole fscache dm_mirror dm_region_hash dm_log sb_edac edac_core x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel crypto_simd joydev input_leds glue_helper ipmi_si iTCO_wdt pcspkr cryptd mei_me iTCO_vendor_support ipmi_devintf sg lpc_ich ipmi_msghandler mei i2c_i801 shpchp mfd_core ioatdma nfsd auth_rpcgss dm_multipath nfs_acl dm_mod lockd grace sunrpc ip_tables ext4 jbd2 mbcache sd_mod mgag200 drm_kms_helper syscopyarea isci sysfillrect sysimgblt ahci igb libsas fb_sys_fops libahci ttm scsi_transport_sas ptp pps_core crc32c_intel dca drm [ 342.769152] i2c_algo_bit libata mlx4_core fjes [last unloaded: ib_srp] [ 342.769157] CPU: 10 PID: 317 Comm: kworker/10:1 Not tainted 4.11.0-rc1+ #97 [ 342.769157] Hardware name: Supermicro X9DRFR/X9DRFR, BIOS 1.0a 09/11/2012 [ 342.769163] Workqueue: srp_remove srp_remove_work [ib_srp] [ 342.769165] Call Trace: [ 342.769173] dump_stack+0x63/0x90 [ 342.769176] __warn+0xcb/0xf0 [ 342.769178] warn_slowpath_null+0x1d/0x20 [ 342.769180] __scsi_remove_device+0x131/0x140 [ 342.769182] scsi_forget_host+0x60/0x70 [ 342.769186] scsi_remove_host+0x77/0x110 [ 342.769189] srp_remove_work+0x90/0x230 [ib_srp] [ 342.769192] process_one_work+0x177/0x430 [ 342.769193] worker_thread+0x4e/0x4b0 [ 342.769195] kthread+0x101/0x140 [ 342.769197] ? process_one_work+0x430/0x430 [ 342.769198] ? kthread_create_on_node+0x60/0x60 [ 342.769201] ret_from_fork+0x2c/0x40 [ 342.769202] ---[ end trace 1eef46ba7887fee3 ]--- [ 342.769210] sd 10:0:0:0: __scsi_remove_device: device_busy = 0 device_blocked = 0 [ 343.020039] sd 10:0:0:0: [sde] Synchronizing SCSI cache [ 352.717659] scsi host10: ib_srp: Got failed path rec status -110 Israel. On 3/9/2017 9:36 PM, Bart Van Assche wrote: On Thu, 2017-03-09 at 18:37 +0200, Israel Rukshin wrote: The bug reproduce when unloading srp module with one port down. sd_shutdown() hangs when __scsi_remove_device() get scsi_device with state SDEV_OFFLINE or SDEV_TRANSPORT_OFFLINE. It hangs because sd_shutdown() is trying to send sync cache command when the device is offline but with SDEV_CANCEL status. The status was changed to SDEV_CANCEL by __scsi_remove_device() before it calls to device_del(). The block layer timeout mechanism doesn't cause the SYNCHRONIZE CACHE command to fail after the timeout expired because the request timer wasn't started. blk_peek_request() that is called from scsi_request_fn() didn't return this request and therefore the request timer didn't start. This commit doesn't accept new commands if the original state was offline. The bug was revealed after commit cff549 ("scsi: proper state checking and module refcount handling in scsi_device_get"). After this commit scsi_device_get() returns error if the device state is SDEV_CANCEL. This eventually leads SRP fast I/O failure timeout handler not to clean the sync cache command because scsi_target_unblock() skip the canceled device. If this timeout handler is set to infinity then the hang remains forever also before commit cff549. How could blk_peek_request() not return a request that has not yet been started? How could a patch that changes scsi_device_get() affect I/O since scsi_device_get() is not called from the I/O path? Anyway, could you try to reproduce the hang with the patch below applied and see whether the output produced by this patch helps to determine what is going on? Thanks, Bart. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba2286652ff6..855548ff4c4d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3018,8 +3018,10 @@ scsi_internal_device_unblock(struct scsi_device *sdev, else sdev->sdev_state = SDEV_CREATED;
Re: [PATCH v2] scsi_sysfs: fix hang when removing scsi device
On Thu, 2017-03-09 at 18:37 +0200, Israel Rukshin wrote: > The bug reproduce when unloading srp module with one port down. > sd_shutdown() hangs when __scsi_remove_device() get scsi_device with > state SDEV_OFFLINE or SDEV_TRANSPORT_OFFLINE. > It hangs because sd_shutdown() is trying to send sync cache command > when the device is offline but with SDEV_CANCEL status. > The status was changed to SDEV_CANCEL by __scsi_remove_device() > before it calls to device_del(). > > The block layer timeout mechanism doesn't cause the SYNCHRONIZE CACHE > command to fail after the timeout expired because the request timer > wasn't started. > blk_peek_request() that is called from scsi_request_fn() didn't return > this request and therefore the request timer didn't start. > > This commit doesn't accept new commands if the original state was offline. > > The bug was revealed after commit cff549 ("scsi: proper state checking > and module refcount handling in scsi_device_get"). > After this commit scsi_device_get() returns error if the device state > is SDEV_CANCEL. > This eventually leads SRP fast I/O failure timeout handler not to clean > the sync cache command because scsi_target_unblock() skip the canceled device. > If this timeout handler is set to infinity then the hang remains forever > also before commit cff549. How could blk_peek_request() not return a request that has not yet been started? How could a patch that changes scsi_device_get() affect I/O since scsi_device_get() is not called from the I/O path? Anyway, could you try to reproduce the hang with the patch below applied and see whether the output produced by this patch helps to determine what is going on? Thanks, Bart. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba2286652ff6..855548ff4c4d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3018,8 +3018,10 @@ scsi_internal_device_unblock(struct scsi_device *sdev, else sdev->sdev_state = SDEV_CREATED; } else if (sdev->sdev_state != SDEV_CANCEL && - sdev->sdev_state != SDEV_OFFLINE) + sdev->sdev_state != SDEV_OFFLINE) { + WARN_ONCE(true, "sdev state = %d\n", sdev->sdev_state); return -EINVAL; + } if (q->mq_ops) { blk_mq_start_stopped_hw_queues(q, false); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 82dfe07b1d47..35aa6b37e199 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1289,6 +1289,13 @@ void __scsi_remove_device(struct scsi_device *sdev) device_unregister(>sdev_dev); transport_remove_device(dev); scsi_dh_remove_device(sdev); + + WARN_ON_ONCE(blk_queue_stopped(sdev->request_queue)); + sdev_printk(KERN_INFO, sdev, + "%s: device_busy = %d device_blocked = %d\n", + __func__, atomic_read(>device_busy), + atomic_read(>device_blocked)); + device_del(dev); } else put_device(>sdev_dev); -- 2.12.0