* [PATCH] scsi host / scsi device ref counting take 2 [1/3]
@ 2003-08-01 20:24 Mike Anderson
2003-08-01 20:25 ` [PATCH] scsi host / scsi device ref counting take 2 [2/3] Mike Anderson
2003-08-02 16:50 ` [PATCH] scsi host / scsi device ref counting take 2 [1/3] Christoph Hellwig
0 siblings, 2 replies; 4+ messages in thread
From: Mike Anderson @ 2003-08-01 20:24 UTC (permalink / raw)
To: linux-scsi
This patch set is against scsi-misc-2.5 cset 1.1595
Christoph, I am sorry I went dead on the last thread. I believe I address
most of your issues except the name of my callback function and the sysfs
attributes for the states. I pulled the sysfs attributes for now and
will send later. We will need to do an update on our attributes
interfaces due to some recent issues discovered by Mochel and Greg KH.
I have also put some slides up on our web site that I used at the OLS
SCSI bof to give a high level call graph of the scsi host and scsi
device reference counting.
https://www-124.ibm.com/developerworks/oss/storageio/gen-io/index.php
I have tested surprise removal with scsi_debug and usb storage.
-andmike
--
Michael Anderson
andmike@us.ibm.com
DESC
This is a cleanup patch for scsi_host removal.
- Addition of a shost_state 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 shost_state 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 | 52 +++++++++++++++++++++++++--------------------
drivers/scsi/scsi.c | 37 ++++++++++++++++++++++++--------
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 | 43 ++++++++++++++++++++++++++-----------
drivers/scsi/sg.c | 3 +-
include/scsi/scsi_device.h | 3 +-
include/scsi/scsi_host.h | 18 ++++++++++++---
11 files changed, 121 insertions(+), 66 deletions(-)
diff -puN drivers/scsi/hosts.c~shost_state drivers/scsi/hosts.c
--- patched-scsi-misc-2.5/drivers/scsi/hosts.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/hosts.c Thu Jul 31 14:32:18 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->shost_state);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ device_for_each_child(&shost->shost_gendev, &recovery,
+ scsi_device_cancel_cb);
+ wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY,
+ &shost->shost_state)));
+}
+/**
+ * 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;
}
/**
@@ -249,21 +254,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;
}
@@ -271,10 +276,12 @@ 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->shost_gendev);
- class_device_get(&shost->shost_classdev);
+ if (test_bit(SHOST_DEL, &shost->shost_state) ||
+ !get_device(&shost->shost_gendev))
+ return NULL;
+ return shost;
}
/**
@@ -283,6 +290,5 @@ void scsi_host_get(struct Scsi_Host *sho
**/
void scsi_host_put(struct Scsi_Host *shost)
{
- class_device_put(&shost->shost_classdev);
put_device(&shost->shost_gendev);
}
diff -puN drivers/scsi/scsi.c~shost_state drivers/scsi/scsi.c
--- patched-scsi-misc-2.5/drivers/scsi/scsi.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi.c Fri Aug 1 07:06:23 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->shost_state))) {
+ 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,
@@ -901,13 +906,21 @@ void scsi_device_put(struct scsi_device
module_put(sdev->host->hostt->module);
}
+int scsi_device_cancel_cb(struct device *dev, void *data)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int recovery = *(int *)data;
+
+ return scsi_device_cancel(sdev, recovery);
+}
+
/**
- * 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 scsi_device *sdev, int recovery)
{
struct scsi_cmnd *scmd;
LIST_HEAD(active_list);
@@ -934,11 +947,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
--- patched-scsi-misc-2.5/drivers/scsi/scsi_debug.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_debug.c Thu Jul 31 14:32:18 2003
@@ -1722,10 +1722,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
--- patched-scsi-misc-2.5/drivers/scsi/scsi_error.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_error.c Thu Jul 31 14:32:18 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->shost_state);
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->shost_state)));
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->shost_state);
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
--- patched-scsi-misc-2.5/drivers/scsi/scsi_lib.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_lib.c Thu Jul 31 14:32:18 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->shost_state) &&
+ shost->host_failed))
scsi_eh_wakeup(shost);
spin_unlock(shost->host_lock);
spin_lock(&sdev->sdev_lock);
@@ -1066,7 +1067,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->shost_state))
return 0;
if (shost->host_busy == 0 && shost->host_blocked) {
/*
diff -puN drivers/scsi/scsi_proc.c~shost_state drivers/scsi/scsi_proc.c
--- patched-scsi-misc-2.5/drivers/scsi/scsi_proc.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_proc.c Thu Jul 31 14:32:18 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
--- patched-scsi-misc-2.5/drivers/scsi/scsi_syms.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_syms.c Thu Jul 31 14:32:18 2003
@@ -86,7 +86,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
--- patched-scsi-misc-2.5/drivers/scsi/scsi_sysfs.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_sysfs.c Fri Aug 1 07:06:23 2003
@@ -54,8 +54,28 @@ static struct class_device_attribute *sc
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->shost_gendev);
+}
+
+static void scsi_host_dev_release(struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct device *parent;
+
+ parent = dev->parent;
+ shost = dev_to_shost(dev);
+ scsi_free_shost(shost);
+ put_device(parent);
+}
+
struct class shost_class = {
.name = "scsi_host",
+ .release = scsi_host_cls_release,
};
static struct class sdev_class = {
@@ -346,16 +366,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)
{
@@ -364,7 +374,7 @@ void scsi_sysfs_init_host(struct Scsi_Ho
shost->host_no);
snprintf(shost->shost_gendev.name, DEVICE_NAME_SIZE, "%s",
shost->hostt->proc_name);
- shost->shost_gendev.release = scsi_host_release;
+ shost->shost_gendev.release = scsi_host_dev_release;
class_device_initialize(&shost->shost_classdev);
shost->shost_classdev.dev = &shost->shost_gendev;
@@ -426,10 +436,14 @@ int scsi_sysfs_add_host(struct Scsi_Host
if (error)
return error;
+ set_bit(SHOST_ADD, &shost->shost_state);
+ get_device(shost->shost_gendev.parent);
+
error = class_device_add(&shost->shost_classdev);
if (error)
goto clean_device;
+ get_device(&shost->shost_gendev);
if (shost->hostt->shost_attrs) {
for (i = 0; shost->hostt->shost_attrs[i]; i++) {
error = class_attr_add(&shost->shost_classdev,
@@ -465,6 +479,11 @@ clean_device:
**/
void scsi_sysfs_remove_host(struct Scsi_Host *shost)
{
- class_device_del(&shost->shost_classdev);
+ unsigned long flags;
+ spin_lock_irqsave(shost->host_lock, flags);
+ set_bit(SHOST_DEL, &shost->shost_state);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ class_device_unregister(&shost->shost_classdev);
device_del(&shost->shost_gendev);
}
diff -puN drivers/scsi/sg.c~shost_state drivers/scsi/sg.c
--- patched-scsi-misc-2.5/drivers/scsi/sg.c~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/sg.c Thu Jul 31 14:32:18 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->shost_state))
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
--- patched-scsi-misc-2.5/include/scsi/scsi_device.h~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/include/scsi/scsi_device.h Fri Aug 1 07:06:23 2003
@@ -93,7 +93,8 @@ 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_cb(struct device *, void *);
+extern int scsi_device_cancel(struct scsi_device *, int);
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
--- patched-scsi-misc-2.5/include/scsi/scsi_host.h~shost_state Thu Jul 31 14:32:18 2003
+++ patched-scsi-misc-2.5-andmike/include/scsi/scsi_host.h Thu Jul 31 14:32:18 2003
@@ -348,6 +348,16 @@ struct scsi_host_template {
struct list_head legacy_hosts;
};
+/*
+ * shost states
+ */
+enum {
+ SHOST_ADD,
+ SHOST_DEL,
+ SHOST_CANCEL,
+ SHOST_RECOVERY,
+};
+
struct Scsi_Host {
struct list_head my_devices;
struct scsi_host_cmd_pool *cmd_pool;
@@ -413,7 +423,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;
@@ -448,6 +457,9 @@ struct Scsi_Host {
unsigned char n_io_port;
unsigned char dma_channel;
unsigned int irq;
+
+
+ unsigned long shost_state;
/* ldm bits */
struct device shost_gendev;
@@ -478,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 void scsi_scan_host(struct Scsi_Host *);
-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);
_
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH] scsi host / scsi device ref counting take 2 [2/3]
2003-08-01 20:24 [PATCH] scsi host / scsi device ref counting take 2 [1/3] Mike Anderson
@ 2003-08-01 20:25 ` Mike Anderson
2003-08-01 20:26 ` [PATCH] scsi host / scsi device ref counting take 2 [3/3] Mike Anderson
2003-08-02 16:50 ` [PATCH] scsi host / scsi device ref counting take 2 [1/3] Christoph Hellwig
1 sibling, 1 reply; 4+ messages in thread
From: Mike Anderson @ 2003-08-01 20:25 UTC (permalink / raw)
To: linux-scsi
-andmike
--
Michael Anderson
andmike@us.ibm.com
DESC
Align usb storage shutdown with changes in the shost shutdown.
EDESC
drivers/usb/storage/usb.c | 14 +-------------
1 files changed, 1 insertion(+), 13 deletions(-)
diff -puN drivers/usb/storage/usb.c~usb_stor_fixups drivers/usb/storage/usb.c
--- patched-scsi-misc-2.5/drivers/usb/storage/usb.c~usb_stor_fixups Fri Aug 1 07:07:17 2003
+++ patched-scsi-misc-2.5-andmike/drivers/usb/storage/usb.c Fri Aug 1 07:07:17 2003
@@ -978,16 +978,9 @@ BadDevice:
static void storage_disconnect(struct usb_interface *intf)
{
struct us_data *us = usb_get_intfdata(intf);
- struct scsi_device *sdev;
US_DEBUGP("storage_disconnect() called\n");
- /* Set devices offline -- need host lock for this */
- scsi_lock(us->host);
- list_for_each_entry(sdev, &us->host->my_devices, siblings)
- sdev->online = 0;
- scsi_unlock(us->host);
-
/* Prevent new USB transfers and stop the current command */
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_stop_transport(us);
@@ -995,12 +988,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) */
_
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH] scsi host / scsi device ref counting take 2 [3/3]
2003-08-01 20:25 ` [PATCH] scsi host / scsi device ref counting take 2 [2/3] Mike Anderson
@ 2003-08-01 20:26 ` Mike Anderson
0 siblings, 0 replies; 4+ messages in thread
From: Mike Anderson @ 2003-08-01 20:26 UTC (permalink / raw)
To: linux-scsi
-andmike
--
Michael Anderson
andmike@us.ibm.com
DESC
This is a cleanup patch for scsi_device removal.
- Addition of sdev_state member to the scsi_device strucuture to contain
"state" of the device instance.
- Added SDEV_ADD, SDEV_DEL, SDEV_CANCEL, SDEV_RECOVERY states for a scsi
device
- Built on previous patch that renamed scsi_set_device_offline to
scsi_device_cancel to use SDEV_CANCEL value.
- Usage of the sdev_state member to stop scsi_device_get's and final cleanup
on access_count going to zero.
- Added newer release functions and reordered scsi device sysfs unregister.
EDESC
drivers/scsi/scsi.c | 36 +++++++++++++++++++----
drivers/scsi/scsi_priv.h | 1
drivers/scsi/scsi_scan.c | 4 +-
drivers/scsi/scsi_sysfs.c | 70 ++++++++++++++++++++++++++++++++++-----------
include/scsi/scsi_device.h | 15 +++++++++
5 files changed, 100 insertions(+), 26 deletions(-)
diff -puN drivers/scsi/scsi.c~sdev_state drivers/scsi/scsi.c
--- patched-scsi-misc-2.5/drivers/scsi/scsi.c~sdev_state Fri Aug 1 07:07:20 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi.c Fri Aug 1 07:07:20 2003
@@ -893,17 +893,41 @@ int scsi_track_queue_full(struct scsi_de
int scsi_device_get(struct scsi_device *sdev)
{
- if (!try_module_get(sdev->host->hostt->module))
- return -ENXIO;
+ struct class *class = class_get(&sdev_class);
+ int error = -ENXIO;
- sdev->access_count++;
- return 0;
+ if (class) {
+ down_write(&class->subsys.rwsem);
+ if (!test_bit(SDEV_DEL, &sdev->sdev_state))
+ if (try_module_get(sdev->host->hostt->module))
+ if (get_device(&sdev->sdev_gendev)) {
+ sdev->access_count++;
+ error = 0;
+ }
+ up_write(&class->subsys.rwsem);
+ class_put(&sdev_class);
+ }
+
+ return error;
}
void scsi_device_put(struct scsi_device *sdev)
{
- sdev->access_count--;
+ struct class *class = class_get(&sdev_class);
+
+ if (!class)
+ return;
+
+ down_write(&class->subsys.rwsem);
module_put(sdev->host->hostt->module);
+ if (--sdev->access_count == 0) {
+ if (test_bit(SDEV_DEL, &sdev->sdev_state))
+ device_del(&sdev->sdev_gendev);
+ }
+ put_device(&sdev->sdev_gendev);
+ up_write(&class->subsys.rwsem);
+
+ class_put(&sdev_class);
}
int scsi_device_cancel_cb(struct device *dev, void *data)
@@ -927,7 +951,7 @@ int scsi_device_cancel(struct scsi_devic
struct list_head *lh, *lh_sf;
unsigned long flags;
- sdev->online = 0;
+ set_bit(SDEV_CANCEL, &sdev->sdev_state);
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
diff -puN drivers/scsi/scsi_priv.h~sdev_state drivers/scsi/scsi_priv.h
--- patched-scsi-misc-2.5/drivers/scsi/scsi_priv.h~sdev_state Fri Aug 1 07:07:20 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_priv.h Fri Aug 1 07:07:20 2003
@@ -121,6 +121,7 @@ extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
extern struct class shost_class;
+extern struct class sdev_class;
extern struct bus_type scsi_bus_type;
#endif /* _SCSI_PRIV_H */
diff -puN drivers/scsi/scsi_scan.c~sdev_state drivers/scsi/scsi_scan.c
--- patched-scsi-misc-2.5/drivers/scsi/scsi_scan.c~sdev_state Fri Aug 1 07:07:20 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_scan.c Fri Aug 1 07:38:00 2003
@@ -288,8 +288,6 @@ void scsi_free_sdev(struct scsi_device *
if (sdev->request_queue)
scsi_free_queue(sdev->request_queue);
- if (sdev->host->hostt->slave_destroy)
- sdev->host->hostt->slave_destroy(sdev);
if (sdev->inquiry)
kfree(sdev->inquiry);
spin_lock_irqsave(sdev->host->host_lock, flags);
@@ -1076,6 +1074,8 @@ struct scsi_device *scsi_add_device(stru
int scsi_remove_device(struct scsi_device *sdev)
{
+ if (sdev->host->hostt->slave_destroy)
+ sdev->host->hostt->slave_destroy(sdev);
scsi_device_unregister(sdev);
return 0;
}
diff -puN drivers/scsi/scsi_sysfs.c~sdev_state drivers/scsi/scsi_sysfs.c
--- patched-scsi-misc-2.5/drivers/scsi/scsi_sysfs.c~sdev_state Fri Aug 1 07:07:20 2003
+++ patched-scsi-misc-2.5-andmike/drivers/scsi/scsi_sysfs.c Fri Aug 1 07:30:58 2003
@@ -78,8 +78,28 @@ struct class shost_class = {
.release = scsi_host_cls_release,
};
-static struct class sdev_class = {
+static void scsi_device_cls_release(struct class_device *class_dev)
+{
+ struct scsi_device *sdev;
+
+ sdev = class_to_sdev(class_dev);
+ put_device(&sdev->sdev_gendev);
+}
+
+static void scsi_device_dev_release(struct device *dev)
+{
+ struct scsi_device *sdev;
+ struct device *parent;
+
+ parent = dev->parent;
+ sdev = to_scsi_device(dev);
+ scsi_free_sdev(sdev);
+ put_device(parent);
+}
+
+struct class sdev_class = {
.name = "scsi_device",
+ .release = scsi_device_cls_release,
};
/* all probing is done in the individual ->probe routines */
@@ -129,7 +149,7 @@ void scsi_sysfs_unregister(void)
*/
#define sdev_show_function(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, char *buf) \
+sdev_show_##field (struct device *dev, char *buf) \
{ \
struct scsi_device *sdev; \
sdev = to_scsi_device(dev); \
@@ -142,7 +162,7 @@ show_##field (struct device *dev, char *
*/
#define sdev_rd_attr(field, format_string) \
sdev_show_function(field, format_string) \
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
+static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL)
/*
@@ -160,7 +180,7 @@ sdev_store_##field (struct device *dev,
snscanf (buf, 20, format_string, &sdev->field); \
return count; \
} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, sdev_store_##field)
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field)
/*
* sdev_rd_attr: create a function and attribute variable for a
@@ -182,7 +202,7 @@ sdev_store_##field (struct device *dev,
} \
return ret; \
} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, sdev_store_##field)
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field)
/*
* scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
@@ -238,15 +258,6 @@ static struct device_attribute *scsi_sys
NULL
};
-static void scsi_device_release(struct device *dev)
-{
- struct scsi_device *sdev;
-
- sdev = to_scsi_device(dev);
- if (!sdev)
- return;
- scsi_free_sdev(sdev);
-}
static struct device_attribute *attr_overridden(
struct device_attribute **attrs,
@@ -295,12 +306,13 @@ int scsi_device_register(struct scsi_dev
{
int error = 0, i;
+ set_bit(SDEV_ADD, &sdev->sdev_state);
device_initialize(&sdev->sdev_gendev);
sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
sdev->sdev_gendev.parent = &sdev->host->shost_gendev;
sdev->sdev_gendev.bus = &scsi_bus_type;
- sdev->sdev_gendev.release = scsi_device_release;
+ sdev->sdev_gendev.release = scsi_device_dev_release;
class_device_initialize(&sdev->sdev_classdev);
sdev->sdev_classdev.dev = &sdev->sdev_gendev;
@@ -313,13 +325,18 @@ int scsi_device_register(struct scsi_dev
printk(KERN_INFO "error 1\n");
return error;
}
+
+ get_device(sdev->sdev_gendev.parent);
+
error = class_device_add(&sdev->sdev_classdev);
if (error) {
printk(KERN_INFO "error 2\n");
- device_unregister(&sdev->sdev_gendev);
+ goto clean_device;
return error;
}
+ get_device(&sdev->sdev_gendev);
+
if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
error = attr_add(&sdev->sdev_gendev,
@@ -340,6 +357,12 @@ int scsi_device_register(struct scsi_dev
}
return error;
+
+clean_device:
+ device_del(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_gendev);
+ return error;
+
}
/**
@@ -348,8 +371,21 @@ int scsi_device_register(struct scsi_dev
**/
void scsi_device_unregister(struct scsi_device *sdev)
{
+ struct class *class = class_get(&sdev_class);
+
class_device_unregister(&sdev->sdev_classdev);
- device_unregister(&sdev->sdev_gendev);
+
+ if (class) {
+ down_write(&class->subsys.rwsem);
+ set_bit(SDEV_DEL, &sdev->sdev_state);
+ if (sdev->access_count == 0)
+ device_del(&sdev->sdev_gendev);
+ up_write(&class->subsys.rwsem);
+ }
+
+ put_device(&sdev->sdev_gendev);
+
+ class_put(&sdev_class);
}
int scsi_register_driver(struct device_driver *drv)
diff -puN include/scsi/scsi_device.h~sdev_state include/scsi/scsi_device.h
--- patched-scsi-misc-2.5/include/scsi/scsi_device.h~sdev_state Fri Aug 1 07:07:20 2003
+++ patched-scsi-misc-2.5-andmike/include/scsi/scsi_device.h Fri Aug 1 07:07:20 2003
@@ -10,6 +10,16 @@ struct scsi_cmnd;
struct scsi_mode_data;
+/*
+ * sdev state
+ */
+enum {
+ SDEV_ADD,
+ SDEV_DEL,
+ SDEV_CANCEL,
+ SDEV_RECOVERY,
+};
+
struct scsi_device {
struct list_head siblings; /* list of all devices on this host */
struct list_head same_target_siblings; /* just the devices sharing same target id */
@@ -86,9 +96,13 @@ struct scsi_device {
struct device sdev_gendev;
struct class_device sdev_classdev;
+
+ unsigned long sdev_state;
};
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
+#define class_to_sdev(d) \
+ container_of(d, struct scsi_device, sdev_classdev)
extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
uint, uint, uint);
@@ -107,5 +121,4 @@ extern int scsi_set_medium_removal(struc
extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
unsigned char *buffer, int len, int timeout,
int retries, struct scsi_mode_data *data);
-
#endif /* _SCSI_SCSI_DEVICE_H */
_
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] scsi host / scsi device ref counting take 2 [1/3]
2003-08-01 20:24 [PATCH] scsi host / scsi device ref counting take 2 [1/3] Mike Anderson
2003-08-01 20:25 ` [PATCH] scsi host / scsi device ref counting take 2 [2/3] Mike Anderson
@ 2003-08-02 16:50 ` Christoph Hellwig
1 sibling, 0 replies; 4+ messages in thread
From: Christoph Hellwig @ 2003-08-02 16:50 UTC (permalink / raw)
To: linux-scsi
On Fri, Aug 01, 2003 at 01:24:31PM -0700, Mike Anderson wrote:
> This patch set is against scsi-misc-2.5 cset 1.1595
>
> Christoph, I am sorry I went dead on the last thread. I believe I address
> most of your issues except the name of my callback function and the sysfs
> attributes for the states. I pulled the sysfs attributes for now and
> will send later. We will need to do an update on our attributes
> interfaces due to some recent issues discovered by Mochel and Greg KH.
The patches look fine to me.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2003-08-02 16:50 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-08-01 20:24 [PATCH] scsi host / scsi device ref counting take 2 [1/3] Mike Anderson
2003-08-01 20:25 ` [PATCH] scsi host / scsi device ref counting take 2 [2/3] Mike Anderson
2003-08-01 20:26 ` [PATCH] scsi host / scsi device ref counting take 2 [3/3] Mike Anderson
2003-08-02 16:50 ` [PATCH] scsi host / scsi device ref counting take 2 [1/3] Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox