From: Brian King <brking@us.ibm.com>
To: Alan Stern <stern@rowland.harvard.edu>
Cc: James Bottomley <James.Bottomley@SteelEye.com>,
Mike Anderson <andmike@us.ibm.com>,
SCSI development list <linux-scsi@vger.kernel.org>
Subject: Re: Questions about scsi_target_reap and starget/sdev lifecyle
Date: Mon, 20 Jun 2005 10:52:34 -0500 [thread overview]
Message-ID: <42B6E642.3000703@us.ibm.com> (raw)
In-Reply-To: <Pine.LNX.4.44L0.0506181554270.3347-100000@netrider.rowland.org>
Alan Stern wrote:
> Don't acquire the scan_mutex in scsi_remove_device. It's
> not needed since there's nothing wrong with removing devices
> during scanning, and it will cause deadlock under certain
> error conditions. (I'm not certain about this either. Will
> removing a device as it's being scanned cause a problem?
> Perhaps there should be a separate version of the routine
> that does acquire the scan_mutex.)
I actually submitted the patch to acquire the scan_mutex in scsi_remove_device
in order to fix an oops I ran into where a device was being deleted while it
was still being scanned. The actual oops was a NULL dentry in sysfs_remove_link.
I would much rather see a __scsi_remove_device API that scsi core and scsi_remove_device
can call that does not acquire the scan_mutex in the paths that make sense to
change. That way scsi_remove_device can maintain its existing behavior.
Brian
>
> Make scsi_forget_host remove all devices, not all targets.
>
> Make the loops to remove devices in scsi_forget_host and
> __scsi_remove_target restart from the beginning every time
> a device is removed (rather than using list_for_each_entry_safe,
> which is very definitely _unsafe_), and skip over devices
> that are already in the SDEV_DEL state.
>
> This fixes several oopses I encountered during testing. Do you think this
> is ready to be applied?
>
> Alan Stern
>
>
>
> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
>
> --- a/include/scsi/scsi_host.h Mon Jun 13 14:57:26 2005
> +++ b/include/scsi/scsi_host.h Fri Jun 17 22:19:09 2005
> @@ -411,6 +411,7 @@
> SHOST_DEL,
> SHOST_CANCEL,
> SHOST_RECOVERY,
> + SHOST_REMOVE,
> };
>
> struct Scsi_Host {
> --- a/drivers/scsi/hosts.c Mon Jun 13 14:57:14 2005
> +++ b/drivers/scsi/hosts.c Fri Jun 17 22:20:19 2005
> @@ -74,8 +74,13 @@
> **/
> void scsi_remove_host(struct Scsi_Host *shost)
> {
> - scsi_forget_host(shost);
> + set_bit(SHOST_REMOVE, &shost->shost_state);
> scsi_host_cancel(shost, 0);
> +
> + down(&shost->scan_mutex); /* Wait for scanning to stop */
> + up(&shost->scan_mutex);
> +
> + scsi_forget_host(shost);
> scsi_proc_host_rm(shost);
>
> set_bit(SHOST_DEL, &shost->shost_state);
> --- a/drivers/scsi/scsi_scan.c Mon Jun 13 14:58:06 2005
> +++ b/drivers/scsi/scsi_scan.c Fri Jun 17 22:59:52 2005
> @@ -843,8 +843,12 @@
> out_free_sdev:
> if (res == SCSI_SCAN_LUN_PRESENT) {
> if (sdevp) {
> - scsi_device_get(sdev);
> - *sdevp = sdev;
> + if (scsi_device_get(sdev) == 0) {
> + *sdevp = sdev;
> + } else {
> + scsi_remove_device(sdev);
> + res = SCSI_SCAN_NO_RESPONSE;
> + }
> }
> } else {
> if (sdev->host->hostt->slave_destroy)
> @@ -1186,22 +1190,28 @@
> uint id, uint lun, void *hostdata)
> {
> struct scsi_device *sdev;
> - struct device *parent = &shost->shost_gendev;
> int res;
> - struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
> + struct scsi_target *starget;
>
> - if (!starget)
> - return ERR_PTR(-ENOMEM);
> + down(&shost->scan_mutex);
> + if (test_bit(SHOST_REMOVE, &shost->shost_state)) {
> + sdev = ERR_PTR(-ENODEV);
> + goto out;
> + }
> + starget = scsi_alloc_target(&shost->shost_gendev, channel, id);
> + if (!starget) {
> + sdev = ERR_PTR(-ENOMEM);
> + goto out;
> + }
>
> get_device(&starget->dev);
> - down(&shost->scan_mutex);
> res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
> if (res != SCSI_SCAN_LUN_PRESENT)
> sdev = ERR_PTR(-ENODEV);
> - up(&shost->scan_mutex);
> scsi_target_reap(starget);
> put_device(&starget->dev);
> -
> +out:
> + up(&shost->scan_mutex);
> return sdev;
> }
> EXPORT_SYMBOL(__scsi_add_device);
> @@ -1222,29 +1232,9 @@
> }
> EXPORT_SYMBOL(scsi_rescan_device);
>
> -/**
> - * scsi_scan_target - scan a target id, possibly including all LUNs on the
> - * target.
> - * @sdevsca: Scsi_Device handle for scanning
> - * @shost: host to scan
> - * @channel: channel to scan
> - * @id: target id to scan
> - *
> - * Description:
> - * Scan the target id on @shost, @channel, and @id. Scan at least LUN
> - * 0, and possibly all LUNs on the target id.
> - *
> - * Use the pre-allocated @sdevscan as a handle for the scanning. This
> - * function sets sdevscan->host, sdevscan->id and sdevscan->lun; the
> - * scanning functions modify sdevscan->lun.
> - *
> - * First try a REPORT LUN scan, if that does not scan the target, do a
> - * sequential scan of LUNs on the target id.
> - **/
> -void scsi_scan_target(struct device *parent, unsigned int channel,
> - unsigned int id, unsigned int lun, int rescan)
> +static void __scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
> + unsigned int id, unsigned int lun, int rescan)
> {
> - struct Scsi_Host *shost = dev_to_shost(parent);
> int bflags = 0;
> int res;
> struct scsi_device *sdev = NULL;
> @@ -1257,7 +1247,7 @@
> return;
>
>
> - starget = scsi_alloc_target(parent, channel, id);
> + starget = scsi_alloc_target(&shost->shost_gendev, channel, id);
>
> if (!starget)
> return;
> @@ -1304,6 +1294,32 @@
>
> put_device(&starget->dev);
> }
> +
> +/**
> + * scsi_scan_target - scan a target id, possibly including all LUNs on the
> + * target.
> + * @parent: host to scan
> + * @channel: channel to scan
> + * @id: target id to scan
> + * @rescan: passed to LUN scanning routines
> + *
> + * Description:
> + * Scan the target id on @shost, @channel, and @id. Scan at least LUN
> + * 0, and possibly all LUNs on the target id.
> + *
> + * First try a REPORT LUN scan, if that does not scan the target, do a
> + * sequential scan of LUNs on the target id.
> + **/
> +void scsi_scan_target(struct device *parent, unsigned int channel,
> + unsigned int id, unsigned int lun, int rescan)
> +{
> + struct Scsi_Host *shost = dev_to_shost(parent);
> +
> + down(&shost->scan_mutex);
> + if (!test_bit(SHOST_REMOVE, &shost->shost_state))
> + __scsi_scan_target(shost, channel, id, lun, rescan);
> + up(&shost->scan_mutex);
> +}
> EXPORT_SYMBOL(scsi_scan_target);
>
> static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
> @@ -1329,10 +1345,10 @@
> order_id = shost->max_id - id - 1;
> else
> order_id = id;
> - scsi_scan_target(&shost->shost_gendev, channel, order_id, lun, rescan);
> + __scsi_scan_target(shost, channel, order_id, lun, rescan);
> }
> else
> - scsi_scan_target(&shost->shost_gendev, channel, id, lun, rescan);
> + __scsi_scan_target(shost, channel, id, lun, rescan);
> }
>
> int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
> @@ -1347,11 +1363,14 @@
> return -EINVAL;
>
> down(&shost->scan_mutex);
> + if (test_bit(SHOST_REMOVE, &shost->shost_state))
> + goto out;
> if (channel == SCAN_WILD_CARD)
> for (channel = 0; channel <= shost->max_channel; channel++)
> scsi_scan_channel(shost, channel, id, lun, rescan);
> else
> scsi_scan_channel(shost, channel, id, lun, rescan);
> +out:
> up(&shost->scan_mutex);
>
> return 0;
> @@ -1383,23 +1402,17 @@
>
> void scsi_forget_host(struct Scsi_Host *shost)
> {
> - struct scsi_target *starget, *tmp;
> + struct scsi_device *sdev;
> unsigned long flags;
>
> - /*
> - * Ok, this look a bit strange. We always look for the first device
> - * on the list as scsi_remove_device removes them from it - thus we
> - * also have to release the lock.
> - * We don't need to get another reference to the device before
> - * releasing the lock as we already own the reference from
> - * scsi_register_device that's release in scsi_remove_device. And
> - * after that we don't look at sdev anymore.
> - */
> +restart:
> spin_lock_irqsave(shost->host_lock, flags);
> - list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
> + list_for_each_entry(sdev, &shost->__devices, siblings) {
> + if (sdev->sdev_state == SDEV_DEL)
> + continue;
> spin_unlock_irqrestore(shost->host_lock, flags);
> - scsi_remove_target(&starget->dev);
> - spin_lock_irqsave(shost->host_lock, flags);
> + scsi_remove_device(sdev);
> + goto restart;
> }
> spin_unlock_irqrestore(shost->host_lock, flags);
> }
> @@ -1426,12 +1439,16 @@
> */
> struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
> {
> - struct scsi_device *sdev;
> + struct scsi_device *sdev = NULL;
> struct scsi_target *starget;
>
> + down(&shost->scan_mutex);
> + if (test_bit(SHOST_REMOVE, &shost->shost_state))
> + goto out;
> +
> starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
> if (!starget)
> - return NULL;
> + goto out;
>
> sdev = scsi_alloc_sdev(starget, 0, NULL);
> if (sdev) {
> @@ -1439,6 +1456,8 @@
> sdev->borken = 0;
> }
> put_device(&starget->dev);
> +out:
> + up(&shost->scan_mutex);
> return sdev;
> }
> EXPORT_SYMBOL(scsi_get_host_dev);
> --- a/drivers/scsi/scsi_sysfs.c Fri Jun 17 22:23:37 2005
> +++ b/drivers/scsi/scsi_sysfs.c Fri Jun 17 22:25:18 2005
> @@ -631,11 +631,8 @@
> **/
> void scsi_remove_device(struct scsi_device *sdev)
> {
> - struct Scsi_Host *shost = sdev->host;
> -
> - down(&shost->scan_mutex);
> if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
> - goto out;
> + return;
>
> class_device_unregister(&sdev->sdev_classdev);
> device_del(&sdev->sdev_gendev);
> @@ -644,8 +641,6 @@
> sdev->host->hostt->slave_destroy(sdev);
> transport_unregister_device(&sdev->sdev_gendev);
> put_device(&sdev->sdev_gendev);
> -out:
> - up(&shost->scan_mutex);
> }
> EXPORT_SYMBOL(scsi_remove_device);
>
> @@ -653,17 +648,20 @@
> {
> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
> unsigned long flags;
> - struct scsi_device *sdev, *tmp;
> + struct scsi_device *sdev;
>
> spin_lock_irqsave(shost->host_lock, flags);
> starget->reap_ref++;
> - list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
> +restart:
> + list_for_each_entry(sdev, &shost->__devices, siblings) {
> if (sdev->channel != starget->channel ||
> - sdev->id != starget->id)
> + sdev->id != starget->id ||
> + sdev->sdev_state == SDEV_DEL)
> continue;
> spin_unlock_irqrestore(shost->host_lock, flags);
> scsi_remove_device(sdev);
> spin_lock_irqsave(shost->host_lock, flags);
> + goto restart;
> }
> spin_unlock_irqrestore(shost->host_lock, flags);
> scsi_target_reap(starget);
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Brian King
eServer Storage I/O
IBM Linux Technology Center
next prev parent reply other threads:[~2005-06-20 15:52 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-06-14 21:27 Questions about scsi_target_reap and starget/sdev lifecyle Alan Stern
2005-06-15 3:28 ` James Bottomley
2005-06-15 20:07 ` Alan Stern
2005-06-15 21:11 ` Alan Stern
2005-06-15 23:03 ` James Bottomley
2005-06-16 2:22 ` Alan Stern
2005-06-16 7:31 ` Mike Anderson
2005-06-16 13:57 ` James Bottomley
2005-06-17 2:01 ` Alan Stern
2005-06-18 20:14 ` Alan Stern
2005-06-20 15:52 ` Brian King [this message]
2005-06-20 16:35 ` Alan Stern
2005-06-20 17:31 ` Patrick Mansfield
2005-06-20 19:24 ` Alan Stern
2005-06-21 17:12 ` Mike Anderson
2005-06-21 17:43 ` Patrick Mansfield
2005-06-21 19:24 ` Mike Anderson
2005-06-21 20:04 ` Alan Stern
2005-06-21 20:10 ` Christoph Hellwig
2005-06-21 20:33 ` Alan Stern
2005-06-21 20:58 ` Mike Anderson
2005-06-21 21:22 ` Alan Stern
2005-06-22 13:44 ` Luben Tuikov
2005-06-22 13:36 ` Luben Tuikov
2005-06-22 15:12 ` Alan Stern
2005-06-22 15:46 ` Luben Tuikov
2005-06-22 16:16 ` Alan Stern
2005-06-22 16:53 ` Luben Tuikov
2005-06-21 21:08 ` Mike Anderson
2005-06-21 21:37 ` Alan Stern
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=42B6E642.3000703@us.ibm.com \
--to=brking@us.ibm.com \
--cc=James.Bottomley@SteelEye.com \
--cc=andmike@us.ibm.com \
--cc=linux-scsi@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.