From: Bart Van Assche <bvanassche@acm.org>
To: linux-scsi <linux-scsi@vger.kernel.org>
Cc: James Bottomley <jbottomley@parallels.com>,
Mike Christie <michaelc@cs.wisc.edu>, Tejun Heo <tj@kernel.org>,
Chanho Min <chanho.min@lge.com>,
David Milburn <dmilburn@redhat.com>
Subject: [PATCH v8 07/10] Make scsi_remove_host() wait for device removal
Date: Tue, 05 Feb 2013 13:49:51 +0100 [thread overview]
Message-ID: <5110FFEF.4080103@acm.org> (raw)
In-Reply-To: <5110FE98.8030209@acm.org>
If removal of a SCSI device has been triggered via sysfs that
device may still be in state SDEV_CANCEL if scsi_remove_host()
is invoked later on and after scsi_remove_host() returns.
SCSI LLDs may start cleaning up host resources needed by their
queuecommand() callback as soon as scsi_remove_host() finished.
Hence scsi_remove_host() must wait until blk_cleanup_queue()
for all devices associated with the host has finished. That
avoids that queuecommand() gets invoked after scsi_remove_host()
finished.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: James Bottomley <JBottomley@Parallels.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/hosts.c | 30 ++++++++++++++++++++++++++++++
drivers/scsi/scsi_priv.h | 1 +
drivers/scsi/scsi_sysfs.c | 1 +
include/scsi/scsi_host.h | 1 +
4 files changed, 33 insertions(+)
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 6ae16cd..b68a013 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -150,12 +150,31 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
}
EXPORT_SYMBOL(scsi_host_set_state);
+/* Return true if and only if scsi_remove_host() is allowed to finish. */
+static bool scsi_remove_host_done(struct Scsi_Host *shost)
+{
+ lockdep_assert_held(shost->host_lock);
+
+ return list_empty(&shost->__devices);
+}
+
+/* Test whether scsi_remove_host() may finish, and if so, wake it up. */
+void scsi_check_remove_host_done(struct Scsi_Host *shost)
+{
+ lockdep_assert_held(shost->host_lock);
+
+ if (scsi_remove_host_done(shost))
+ wake_up(&shost->remove_host);
+}
+
/**
* scsi_remove_host - remove a scsi host
* @shost: a pointer to a scsi host to remove
**/
void scsi_remove_host(struct Scsi_Host *shost)
{
+ DEFINE_WAIT(wait);
+
mutex_lock(&shost->scan_mutex);
spin_lock_irq(shost->host_lock);
if (scsi_host_set_state(shost, SHOST_CANCEL))
@@ -174,6 +193,16 @@ void scsi_remove_host(struct Scsi_Host *shost)
spin_lock_irq(shost->host_lock);
if (scsi_host_set_state(shost, SHOST_DEL))
BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
+ while (!scsi_remove_host_done(shost)) {
+ prepare_to_wait_exclusive(&shost->remove_host, &wait,
+ TASK_INTERRUPTIBLE);
+ if (scsi_remove_host_done(shost))
+ break;
+ spin_unlock_irq(shost->host_lock);
+ schedule();
+ spin_lock_irq(shost->host_lock);
+ }
+ finish_wait(&shost->remove_host, &wait);
spin_unlock_irq(shost->host_lock);
transport_unregister_device(&shost->shost_gendev);
@@ -349,6 +378,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets);
+ init_waitqueue_head(&shost->remove_host);
INIT_LIST_HEAD(&shost->eh_cmd_q);
INIT_LIST_HEAD(&shost->starved_list);
init_waitqueue_head(&shost->host_wait);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 8f9a0ca..882c823 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -26,6 +26,7 @@ struct scsi_nl_hdr;
/* hosts.c */
extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
+extern void scsi_check_remove_host_done(struct Scsi_Host *shost);
/* scsi.c */
extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 7c1935b..bd51d65 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -345,6 +345,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
starget->reap_ref++;
list_del(&sdev->siblings);
list_del(&sdev->same_target_siblings);
+ scsi_check_remove_host_done(sdev->host);
spin_unlock_irqrestore(sdev->host->host_lock, flags);
cancel_work_sync(&sdev->event_work);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 4908480..1b7fd89 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -577,6 +577,7 @@ struct Scsi_Host {
struct completion * eh_action; /* Wait for specific actions on the
host. */
wait_queue_head_t host_wait;
+ wait_queue_head_t remove_host;
struct scsi_host_template *hostt;
struct scsi_transport_template *transportt;
--
1.7.10.4
next prev parent reply other threads:[~2013-02-05 12:49 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-05 12:44 [PATCH v8 0/10] More device removal fixes Bart Van Assche
2013-02-05 12:45 ` [PATCH v8 01/10] Fix race between starved list processing and device removal Bart Van Assche
2013-02-05 12:46 ` [PATCH v8 02/10] Remove get_device() / put_device() pair from scsi_request_fn() Bart Van Assche
2013-02-05 12:47 ` [PATCH v8 03/10] Introduce scsi_device_being_removed() Bart Van Assche
2013-02-05 12:47 ` [PATCH v8 04/10] Remove offline devices when removing a host Bart Van Assche
2013-02-05 12:48 ` [PATCH v8 05/10] Disallow changing the device state via sysfs into "deleted" Bart Van Assche
2013-02-05 12:49 ` [PATCH v8 06/10] Avoid saving/restoring interrupt state inside scsi_remove_host() Bart Van Assche
2013-02-05 12:49 ` Bart Van Assche [this message]
2013-02-05 12:50 ` [PATCH v8 08/10] Make scsi_remove_host() wait until error handling finished Bart Van Assche
2013-02-05 12:51 ` [PATCH v8 09/10] Avoid that scsi_device_set_state() triggers a race Bart Van Assche
2013-02-05 12:51 ` [PATCH v8 10/10] Save and restore host_scribble during error handling Bart Van Assche
2013-02-06 22:31 ` [PATCH v8 0/10] More device removal fixes Joe Lawrence
2013-02-07 10:40 ` Bart Van Assche
2013-02-07 11:33 ` Bart Van Assche
2013-02-08 23:29 ` Joe Lawrence
2013-02-09 9:28 ` Bart Van Assche
2013-02-11 20:36 ` Bart Van Assche
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=5110FFEF.4080103@acm.org \
--to=bvanassche@acm.org \
--cc=chanho.min@lge.com \
--cc=dmilburn@redhat.com \
--cc=jbottomley@parallels.com \
--cc=linux-scsi@vger.kernel.org \
--cc=michaelc@cs.wisc.edu \
--cc=tj@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).