From: Mike Anderson <andmike@us.ibm.com>
To: linux-scsi@vger.kernel.org
Subject: [PATCH] scsi host/scsi device ref count cleanup 3/4
Date: Tue, 8 Jul 2003 15:27:07 -0700 [thread overview]
Message-ID: <20030708222706.GD2232@beaverton.ibm.com> (raw)
In-Reply-To: <20030708222622.GC2232@beaverton.ibm.com>
-andmike
--
Michael Anderson
andmike@us.ibm.com
DESC
This is a cleanup patch for scsi_host removal.
- Addition of a host_flags member to the scsi_host strucuture to
contain "state" of the host instance.
- Added SHOST_ADD, SHOST_DEL, SHOST_CANCEL, SHOST_RECOVERY states
for a scsi host
- Addtion / rename of a new function scsi_host_cancel to cancel
IOs in flight.
- Usage of the host_flags flags member to stop scsi_host_get's and
calls to LLDD queucommand under certain states.
- Reordered some of the scsi host sysfs unregistration.
EDESC
drivers/scsi/hosts.c | 62 +++++++++++++++++++++++++++------------------
drivers/scsi/scsi.c | 31 +++++++++++++++-------
drivers/scsi/scsi_debug.c | 5 ---
drivers/scsi/scsi_error.c | 7 ++---
drivers/scsi/scsi_lib.c | 5 ++-
drivers/scsi/scsi_proc.c | 12 ++++----
drivers/scsi/scsi_syms.c | 2 -
drivers/scsi/scsi_sysfs.c | 44 ++++++++++++++++++++++---------
drivers/scsi/sg.c | 3 +-
drivers/usb/storage/usb.c | 7 -----
include/scsi/scsi_device.h | 2 -
include/scsi/scsi_host.h | 16 +++++++++--
12 files changed, 122 insertions(+), 74 deletions(-)
diff -puN drivers/scsi/hosts.c~shost_state drivers/scsi/hosts.c
--- remove-scsi-misc-2.5/drivers/scsi/hosts.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/hosts.c Tue Jul 8 14:19:52 2003
@@ -39,30 +39,35 @@
static int scsi_host_next_hn; /* host_no for next new host */
+
/**
- * scsi_remove_host - check a scsi host for release and release
- * @shost: a pointer to a scsi host to release
- *
- * Return value:
- * 0 on Success / 1 on Failure
+ * scsi_host_cancel - cancel outstanding IO to this host
+ * @shost: pointer to struct Scsi_Host
+ * recovery: recovery requested to run.
**/
-int scsi_remove_host(struct Scsi_Host *shost)
+void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
{
- struct scsi_device *sdev;
+ unsigned long flags;
- /*
- * FIXME Do ref counting. We force all of the devices offline to
- * help prevent race conditions where other hosts/processors could
- * try and get in and queue a command.
- */
- list_for_each_entry(sdev, &shost->my_devices, siblings)
- sdev->online = FALSE;
+ spin_lock_irqsave(shost->host_lock, flags);
+ __set_bit(SHOST_CANCEL, &shost->host_flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ device_for_each_child(&shost->host_gendev, &recovery,
+ scsi_device_cancel);
+ wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY,
+ &shost->host_flags)));
+}
+/**
+ * scsi_remove_host - remove a scsi host
+ * @shost: a pointer to a scsi host to remove
+ **/
+void scsi_remove_host(struct Scsi_Host *shost)
+{
+ scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost);
scsi_forget_host(shost);
scsi_sysfs_remove_host(shost);
-
- return 0;
}
/**
@@ -93,7 +98,7 @@ int scsi_add_host(struct Scsi_Host *shos
scsi_proc_host_add(shost);
scsi_scan_host(shost);
}
-
+
return error;
}
@@ -259,21 +264,21 @@ struct Scsi_Host *scsi_host_lookup(unsig
{
struct class *class = class_get(&shost_class);
struct class_device *cdev;
- struct Scsi_Host *shost = NULL, *p;
+ struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
if (class) {
down_read(&class->subsys.rwsem);
list_for_each_entry(cdev, &class->children, node) {
p = class_to_shost(cdev);
if (p->host_no == hostnum) {
- scsi_host_get(p);
- shost = p;
+ shost = scsi_host_get(p);
break;
}
}
up_read(&class->subsys.rwsem);
}
+ class_put(&shost_class);
return shost;
}
@@ -281,10 +286,20 @@ struct Scsi_Host *scsi_host_lookup(unsig
* *scsi_host_get - inc a Scsi_Host ref count
* @shost: Pointer to Scsi_Host to inc.
**/
-void scsi_host_get(struct Scsi_Host *shost)
+struct Scsi_Host * scsi_host_get(struct Scsi_Host *shost)
{
- get_device(&shost->host_gendev);
- class_device_get(&shost->class_dev);
+ struct Scsi_Host *res_shost = shost;
+
+ if (res_shost) {
+ if (!test_bit(SHOST_DEL, &shost->host_flags)) {
+ if (!get_device(&res_shost->host_gendev))
+ res_shost = ERR_PTR(-ENXIO);
+ } else {
+ res_shost = ERR_PTR(-ENXIO);
+ }
+ }
+
+ return res_shost;
}
/**
@@ -293,6 +308,5 @@ void scsi_host_get(struct Scsi_Host *sho
**/
void scsi_host_put(struct Scsi_Host *shost)
{
- class_device_put(&shost->class_dev);
put_device(&shost->host_gendev);
}
diff -puN drivers/scsi/scsi.c~shost_state drivers/scsi/scsi.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi.c Tue Jul 8 14:19:52 2003
@@ -370,7 +370,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
struct Scsi_Host *host = cmd->device->host;
unsigned long flags = 0;
unsigned long timeout;
- int rtn = 1;
+ int rtn = 0;
/* Assign a unique nonzero serial_number. */
/* XXX(hch): this is racy */
@@ -444,7 +444,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
host->hostt->queuecommand));
spin_lock_irqsave(host->host_lock, flags);
- rtn = host->hostt->queuecommand(cmd, scsi_done);
+ if (unlikely(test_bit(SHOST_CANCEL, &host->host_flags))) {
+ cmd->result = (DID_NO_CONNECT << 16);
+ scsi_done(cmd);
+ } else {
+ rtn = host->hostt->queuecommand(cmd, scsi_done);
+ }
spin_unlock_irqrestore(host->host_lock, flags);
if (rtn) {
scsi_queue_insert(cmd,
@@ -902,17 +907,19 @@ void scsi_device_put(struct scsi_device
}
/**
- * scsi_set_device_offline - set scsi_device offline
- * @sdev: pointer to struct scsi_device to offline.
+ * scsi_device_cancel - cancel outstanding IO to this device
+ * @sdev: pointer to struct scsi_device
+ * @data: pointer to cancel value.
*
- * Locks: host_lock held on entry.
**/
-void scsi_set_device_offline(struct scsi_device *sdev)
+int scsi_device_cancel(struct device *dev, void *data)
{
struct scsi_cmnd *scmd;
LIST_HEAD(active_list);
struct list_head *lh, *lh_sf;
unsigned long flags;
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned int recovery = *(unsigned int *)data;
sdev->online = 0;
@@ -934,11 +941,17 @@ void scsi_set_device_offline(struct scsi
if (!list_empty(&active_list)) {
list_for_each_safe(lh, lh_sf, &active_list) {
scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
- scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD);
+ list_del_init(lh);
+ if (recovery) {
+ scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD);
+ } else {
+ scmd->result = (DID_ABORT << 16);
+ scsi_finish_command(scmd);
+ }
}
- } else {
- /* FIXME: Send online state change hotplug event */
}
+
+ return 0;
}
MODULE_DESCRIPTION("SCSI core");
diff -puN drivers/scsi/scsi_debug.c~shost_state drivers/scsi/scsi_debug.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi_debug.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi_debug.c Tue Jul 8 14:19:52 2003
@@ -1721,10 +1721,7 @@ static int sdebug_driver_remove(struct d
return -ENODEV;
}
- if (scsi_remove_host(sdbg_host->shost)) {
- printk(KERN_ERR "%s: scsi_remove_host failed\n", __FUNCTION__);
- return -EBUSY;
- }
+ scsi_remove_host(sdbg_host->shost);
list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
diff -puN drivers/scsi/scsi_error.c~shost_state drivers/scsi/scsi_error.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi_error.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi_error.c Tue Jul 8 14:19:52 2003
@@ -84,7 +84,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
*/
scmd->serial_number_at_timeout = scmd->serial_number;
list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
- shost->in_recovery = 1;
+ set_bit(SHOST_RECOVERY, &shost->host_flags);
shost->host_failed++;
scsi_eh_wakeup(shost);
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -187,7 +187,7 @@ void scsi_times_out(struct scsi_cmnd *sc
**/
int scsi_block_when_processing_errors(struct scsi_device *sdev)
{
- wait_event(sdev->host->host_wait, (sdev->host->in_recovery == 0));
+ wait_event(sdev->host->host_wait, (!test_bit(SHOST_RECOVERY, &sdev->host->host_flags)));
SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__,
sdev->online));
@@ -1389,7 +1389,7 @@ static void scsi_restart_operations(stru
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
__FUNCTION__));
- shost->in_recovery = 0;
+ clear_bit(SHOST_RECOVERY, &shost->host_flags);
wake_up(&shost->host_wait);
@@ -1599,7 +1599,6 @@ void scsi_error_handler(void *data)
* that's fine. If the user sent a signal to this thing, we are
* potentially in real danger.
*/
- shost->in_recovery = 0;
shost->eh_active = 0;
shost->ehandler = NULL;
diff -puN drivers/scsi/scsi_lib.c~shost_state drivers/scsi/scsi_lib.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi_lib.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi_lib.c Tue Jul 8 14:19:52 2003
@@ -318,7 +318,8 @@ void scsi_device_unbusy(struct scsi_devi
spin_lock_irqsave(shost->host_lock, flags);
shost->host_busy--;
- if (unlikely(shost->in_recovery && shost->host_failed))
+ if (unlikely(test_bit(SHOST_RECOVERY, &shost->host_flags) &&
+ shost->host_failed))
scsi_eh_wakeup(shost);
spin_unlock(shost->host_lock);
spin_lock(&sdev->sdev_lock);
@@ -1080,7 +1081,7 @@ static inline int scsi_host_queue_ready(
struct Scsi_Host *shost,
struct scsi_device *sdev)
{
- if (shost->in_recovery)
+ if (test_bit(SHOST_RECOVERY, &shost->host_flags))
return 0;
if (shost->host_busy == 0 && shost->host_blocked) {
/*
diff -puN drivers/scsi/scsi_proc.c~shost_state drivers/scsi/scsi_proc.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi_proc.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi_proc.c Tue Jul 8 14:19:52 2003
@@ -190,11 +190,11 @@ static int scsi_add_single_device(uint h
{
struct Scsi_Host *shost;
struct scsi_device *sdev;
- int error = -ENODEV;
+ int error = -ENXIO;
shost = scsi_host_lookup(host);
- if (!shost)
- return -ENODEV;
+ if (IS_ERR(shost))
+ return PTR_ERR(shost);
if (!scsi_find_device(shost, channel, id, lun)) {
sdev = scsi_add_device(shost, channel, id, lun);
@@ -212,11 +212,11 @@ static int scsi_remove_single_device(uin
{
struct scsi_device *sdev;
struct Scsi_Host *shost;
- int error = -ENODEV;
+ int error = -ENXIO;
shost = scsi_host_lookup(host);
- if (!shost)
- return -ENODEV;
+ if (IS_ERR(shost))
+ return PTR_ERR(shost);
sdev = scsi_find_device(shost, channel, id, lun);
if (!sdev)
goto out;
diff -puN drivers/scsi/scsi_syms.c~shost_state drivers/scsi/scsi_syms.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi_syms.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi_syms.c Tue Jul 8 14:19:52 2003
@@ -85,7 +85,7 @@ EXPORT_SYMBOL(scsi_device_get);
EXPORT_SYMBOL(scsi_device_put);
EXPORT_SYMBOL(scsi_add_device);
EXPORT_SYMBOL(scsi_remove_device);
-EXPORT_SYMBOL(scsi_set_device_offline);
+EXPORT_SYMBOL(scsi_device_cancel);
EXPORT_SYMBOL(__scsi_mode_sense);
EXPORT_SYMBOL(scsi_mode_sense);
diff -puN drivers/scsi/scsi_sysfs.c~shost_state drivers/scsi/scsi_sysfs.c
--- remove-scsi-misc-2.5/drivers/scsi/scsi_sysfs.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/scsi_sysfs.c Tue Jul 8 14:19:52 2003
@@ -44,6 +44,7 @@ shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
shost_rd_attr(sg_tablesize, "%hu\n");
shost_rd_attr(unchecked_isa_dma, "%d\n");
+shost_rd_attr(host_flags, "%lx\n");
struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_unique_id,
@@ -51,11 +52,30 @@ struct class_device_attribute *scsi_sysf
&class_device_attr_cmd_per_lun,
&class_device_attr_sg_tablesize,
&class_device_attr_unchecked_isa_dma,
+ &class_device_attr_host_flags,
NULL
};
+static void scsi_host_cls_release(struct class_device *class_dev)
+{
+ struct Scsi_Host *shost;
+
+ shost = class_to_shost(class_dev);
+ put_device(&shost->host_gendev);
+}
+
+static void scsi_host_dev_release(struct device *dev)
+{
+ struct Scsi_Host *shost;
+
+ device_del(dev);
+ shost = dev_to_shost(dev);
+ scsi_free_shost(shost);
+}
+
struct class shost_class = {
.name = "scsi_host",
+ .release = scsi_host_cls_release,
};
static struct class sdev_class = {
@@ -302,16 +322,6 @@ int scsi_register_interface(struct class
return class_interface_register(intf);
}
-static void scsi_host_release(struct device *dev)
-{
- struct Scsi_Host *shost;
-
- shost = dev_to_shost(dev);
- if (!shost)
- return;
-
- scsi_free_shost(shost);
-}
void scsi_sysfs_init_host(struct Scsi_Host *shost)
{
@@ -320,13 +330,14 @@ void scsi_sysfs_init_host(struct Scsi_Ho
shost->host_no);
snprintf(shost->host_gendev.name, DEVICE_NAME_SIZE, "%s",
shost->hostt->proc_name);
- shost->host_gendev.release = scsi_host_release;
+ shost->host_gendev.release = scsi_host_dev_release;
class_device_initialize(&shost->class_dev);
shost->class_dev.dev = &shost->host_gendev;
shost->class_dev.class = &shost_class;
snprintf(shost->class_dev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
+ get_device(&shost->host_gendev);
}
/**
@@ -355,6 +366,8 @@ int scsi_sysfs_add_host(struct Scsi_Host
if (error)
goto clean_class;
+ set_bit(SHOST_ADD, &shost->host_flags);
+
return error;
clean_class:
@@ -371,8 +384,13 @@ clean_device:
**/
void scsi_sysfs_remove_host(struct Scsi_Host *shost)
{
- class_device_del(&shost->class_dev);
- device_del(&shost->host_gendev);
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ __set_bit(SHOST_DEL, &shost->host_flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ class_device_unregister(&shost->class_dev);
}
/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute
diff -puN drivers/scsi/sg.c~shost_state drivers/scsi/sg.c
--- remove-scsi-misc-2.5/drivers/scsi/sg.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/scsi/sg.c Tue Jul 8 14:19:52 2003
@@ -954,7 +954,8 @@ sg_ioctl(struct inode *inode, struct fil
if (sdp->detached)
return -ENODEV;
if (filp->f_flags & O_NONBLOCK) {
- if (sdp->device->host->in_recovery)
+ if (test_bit(SHOST_RECOVERY,
+ &sdp->device->host->host_flags))
return -EBUSY;
} else if (!scsi_block_when_processing_errors(sdp->device))
return -EBUSY;
diff -puN include/scsi/scsi_device.h~shost_state include/scsi/scsi_device.h
--- remove-scsi-misc-2.5/include/scsi/scsi_device.h~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/include/scsi/scsi_device.h Tue Jul 8 14:19:52 2003
@@ -94,7 +94,7 @@ struct scsi_device {
extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
uint, uint, uint);
extern int scsi_remove_device(struct scsi_device *);
-extern void scsi_set_device_offline(struct scsi_device *);
+extern int scsi_device_cancel(struct device *, void *);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
diff -puN include/scsi/scsi_host.h~shost_state include/scsi/scsi_host.h
--- remove-scsi-misc-2.5/include/scsi/scsi_host.h~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/include/scsi/scsi_host.h Tue Jul 8 14:19:52 2003
@@ -348,6 +348,14 @@ struct scsi_host_template {
struct list_head legacy_hosts;
};
+/*
+ * shost flags
+ */
+#define SHOST_ADD 1
+#define SHOST_DEL 2
+#define SHOST_CANCEL 3
+#define SHOST_RECOVERY 4
+
struct Scsi_Host {
struct list_head my_devices;
struct scsi_host_cmd_pool *cmd_pool;
@@ -413,7 +421,6 @@ struct Scsi_Host {
short unsigned int sg_tablesize;
short unsigned int max_sectors;
- unsigned in_recovery:1;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned highmem_io:1;
@@ -454,6 +461,9 @@ struct Scsi_Host {
unsigned char n_io_port;
unsigned char dma_channel;
unsigned int irq;
+
+
+ unsigned long host_flags;
/*
@@ -480,8 +490,8 @@ struct Scsi_Host {
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
extern int scsi_add_host(struct Scsi_Host *, struct device *);
-extern int scsi_remove_host(struct Scsi_Host *);
-extern void scsi_host_get(struct Scsi_Host *);
+extern void scsi_remove_host(struct Scsi_Host *);
+extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
extern void scsi_host_put(struct Scsi_Host *t);
extern struct Scsi_Host *scsi_host_lookup(unsigned short);
diff -puN drivers/usb/storage/usb.c~shost_state drivers/usb/storage/usb.c
--- remove-scsi-misc-2.5/drivers/usb/storage/usb.c~shost_state Tue Jul 8 14:19:52 2003
+++ remove-scsi-misc-2.5-andmike/drivers/usb/storage/usb.c Tue Jul 8 14:19:52 2003
@@ -993,12 +993,7 @@ static void storage_disconnect(struct us
/* Dissociate from the USB device */
dissociate_dev(us);
- /* Begin the SCSI host removal sequence */
- if (scsi_remove_host(us->host)) {
- US_DEBUGP("-- SCSI refused to remove the host\n");
- BUG();
- return;
- }
+ scsi_remove_host(us->host);
/* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */
_
next prev parent reply other threads:[~2003-07-08 22:09 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-07-08 22:24 [PATCH] scsi host/scsi device ref count cleanup 0/4 Mike Anderson
2003-07-08 22:25 ` [PATCH] scsi host/scsi device ref count cleanup 1/4 Mike Anderson
2003-07-08 22:26 ` [PATCH] scsi host/scsi device ref count cleanup 2/4 Mike Anderson
2003-07-08 22:27 ` Mike Anderson [this message]
2003-07-08 22:27 ` [PATCH] scsi host/scsi device ref count cleanup 4/4 Mike Anderson
2003-07-09 8:15 ` (unknown) Christoph Hellwig
2003-07-09 7:53 ` [PATCH] scsi host/scsi device ref count cleanup 3/4 Christoph Hellwig
2003-07-10 14:03 ` Mike Anderson
2003-07-13 13:39 ` Christoph Hellwig
2003-07-09 7:39 ` [PATCH] scsi host/scsi device ref count cleanup 2/4 Christoph Hellwig
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=20030708222706.GD2232@beaverton.ibm.com \
--to=andmike@us.ibm.com \
--cc=linux-scsi@vger.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).