Commit f7ad2011 authored by Mike Anderson's avatar Mike Anderson Committed by James Bottomley

[PATCH] Add release function to sd for scsi_disk structure

This patch removes the delay in calling device_del on the sdev struct
device during a surprise removal event. Reference counting functions for
sd's scsi_disk structure where also added to fix issues of unregistering
when a sd is open.

I have tested this patch using scsi_debug with differnt combinations of
adds / removes. I mounted both partitioned and un-partitioned sd disks,
remove the host, and then did a umount. The ref count debug output shows
the objects staying in place prior to the umount and cleaning up once
the umount is called.

This patch fixes an issue with a delayed call of device_del on the
sdev_gendev struct device.
	- Remove the delayed call to device_del.
	- Add kobject to sd scsi_disk structure.
	- Add release function for scsi_disk kobject.
	- Add get / put functions for scsi_disk and calls to these
	  functions.

 drivers/scsi/scsi.c       |    4 --
 drivers/scsi/scsi_sysfs.c |    3 --
 drivers/scsi/sd.c         |   63 ++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 57 insertions(+), 13 deletions(-)
parent 92933518
...@@ -914,9 +914,7 @@ void scsi_device_put(struct scsi_device *sdev) ...@@ -914,9 +914,7 @@ void scsi_device_put(struct scsi_device *sdev)
return; return;
module_put(sdev->host->hostt->module); module_put(sdev->host->hostt->module);
if (atomic_dec_and_test(&sdev->access_count)) atomic_dec(&sdev->access_count);
if (test_bit(SDEV_DEL, &sdev->sdev_state))
device_del(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
class_put(&sdev_class); class_put(&sdev_class);
} }
......
...@@ -412,8 +412,7 @@ void scsi_remove_device(struct scsi_device *sdev) ...@@ -412,8 +412,7 @@ void scsi_remove_device(struct scsi_device *sdev)
set_bit(SDEV_DEL, &sdev->sdev_state); set_bit(SDEV_DEL, &sdev->sdev_state);
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (!atomic_read(&sdev->access_count)) device_del(&sdev->sdev_gendev);
device_del(&sdev->sdev_gendev);
up_write(&class->subsys.rwsem); up_write(&class->subsys.rwsem);
} }
......
...@@ -74,9 +74,16 @@ ...@@ -74,9 +74,16 @@
*/ */
#define SD_MAX_RETRIES 5 #define SD_MAX_RETRIES 5
static void scsi_disk_release (struct kobject *kobj);
static struct kobj_type scsi_disk_kobj_type = {
.release = scsi_disk_release,
};
struct scsi_disk { struct scsi_disk {
struct scsi_driver *driver; /* always &sd_template */ struct scsi_driver *driver; /* always &sd_template */
struct scsi_device *device; struct scsi_device *device;
struct kobject kobj;
struct gendisk *disk; struct gendisk *disk;
unsigned int openers; /* protected by BKL for now, yuck */ unsigned int openers; /* protected by BKL for now, yuck */
sector_t capacity; /* size in 512-byte sectors */ sector_t capacity; /* size in 512-byte sectors */
...@@ -87,6 +94,7 @@ struct scsi_disk { ...@@ -87,6 +94,7 @@ struct scsi_disk {
unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned RCD : 1; /* state of disk RCD bit, unused */
}; };
static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG];
static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;
...@@ -128,11 +136,33 @@ static int sd_major(int major_idx) ...@@ -128,11 +136,33 @@ static int sd_major(int major_idx)
} }
} }
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kobj);
static inline struct scsi_disk *scsi_disk(struct gendisk *disk) static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
{ {
return container_of(disk->private_data, struct scsi_disk, driver); return container_of(disk->private_data, struct scsi_disk, driver);
} }
static int scsi_disk_get(struct scsi_disk *sdkp)
{
if (!kobject_get(&sdkp->kobj))
goto out;
if (scsi_device_get(sdkp->device))
goto out_put_kobj;
return 0;
out_put_kobj:
kobject_put(&sdkp->kobj);
out:
return -ENXIO;
}
static void scsi_disk_put(struct scsi_disk *sdkp)
{
scsi_device_put(sdkp->device);
kobject_put(&sdkp->kobj);
}
/** /**
* sd_init_command - build a scsi (read or write) command from * sd_init_command - build a scsi (read or write) command from
* information in the request structure. * information in the request structure.
...@@ -352,15 +382,17 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -352,15 +382,17 @@ static int sd_open(struct inode *inode, struct file *filp)
{ {
struct gendisk *disk = inode->i_bdev->bd_disk; struct gendisk *disk = inode->i_bdev->bd_disk;
struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdev = sdkp->device; struct scsi_device *sdev;
int retval; int retval;
SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name)); SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name));
retval = scsi_device_get(sdev); retval = scsi_disk_get(sdkp);
if (retval) if (retval)
return retval; return retval;
sdev = sdkp->device;
/* /*
* If the device is in error recovery, wait until it is done. * If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it. * If the device is offline, then disallow any access to it.
...@@ -406,7 +438,7 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -406,7 +438,7 @@ static int sd_open(struct inode *inode, struct file *filp)
return 0; return 0;
error_out: error_out:
scsi_device_put(sdev); scsi_disk_put(sdkp);
return retval; return retval;
} }
...@@ -438,7 +470,7 @@ static int sd_release(struct inode *inode, struct file *filp) ...@@ -438,7 +470,7 @@ static int sd_release(struct inode *inode, struct file *filp)
* XXX and what if there are packets in flight and this close() * XXX and what if there are packets in flight and this close()
* XXX is followed by a "rmmod sd_mod"? * XXX is followed by a "rmmod sd_mod"?
*/ */
scsi_device_put(sdev); scsi_disk_put(sdkp);
return 0; return 0;
} }
...@@ -1279,6 +1311,10 @@ static int sd_probe(struct device *dev) ...@@ -1279,6 +1311,10 @@ static int sd_probe(struct device *dev)
if (!sdkp) if (!sdkp)
goto out; goto out;
memset (sdkp, 0, sizeof(*sdkp));
kobject_init(&sdkp->kobj);
sdkp->kobj.ktype = &scsi_disk_kobj_type;
gd = alloc_disk(16); gd = alloc_disk(16);
if (!gd) if (!gd)
goto out_free; goto out_free;
...@@ -1357,16 +1393,27 @@ static int sd_remove(struct device *dev) ...@@ -1357,16 +1393,27 @@ static int sd_remove(struct device *dev)
struct scsi_disk *sdkp = dev_get_drvdata(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev);
del_gendisk(sdkp->disk); del_gendisk(sdkp->disk);
sd_shutdown(dev);
kobject_put(&sdkp->kobj);
return 0;
}
/**
* scsi_disk_release - Called to free the scsi_disk structure
* @kobj: pointer to embedded kobject
**/
static void scsi_disk_release(struct kobject *kobj)
{
struct scsi_disk *sdkp = to_scsi_disk(kobj);
put_disk(sdkp->disk);
spin_lock(&sd_index_lock); spin_lock(&sd_index_lock);
clear_bit(sdkp->index, sd_index_bits); clear_bit(sdkp->index, sd_index_bits);
spin_unlock(&sd_index_lock); spin_unlock(&sd_index_lock);
sd_shutdown(dev);
put_disk(sdkp->disk);
kfree(sdkp); kfree(sdkp);
return 0;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment