Commit ee89063d authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Christoph Hellwig

[PATCH] abstract out more scsi_device acess out of the low-level drivers

Two new helpers: scsi_device_get and scsi_device_put that get/release a
reference to the underlying HBA driver and increment/decrement
->access_count.  Cleanup ->attach/->detach routines in the upper layer
drivers a bit to consolidate the error pathes once we're cleaning them
up.

->attach and ->detach in upper layer drivers are mandatory now (not
having them would be rather pointless).

(note that the sd.c changes are not in this patch, it'll be part of
my next, bigger patch)
parent a8ba842f
...@@ -4234,14 +4234,14 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4234,14 +4234,14 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
#endif #endif
return (-EBUSY); return (-EBUSY);
} }
if (!try_module_get(STp->device->host->hostt->module)) {
if (!scsi_device_get(STp->device)) {
write_unlock(&os_scsi_tapes_lock); write_unlock(&os_scsi_tapes_lock);
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "%s:D: Failed try_module_get.\n", name); printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
#endif #endif
return (-ENXIO); return (-ENXIO);
} }
STp->device->access_count++;
filp->private_data = STp; filp->private_data = STp;
STp->in_use = 1; STp->in_use = 1;
write_unlock(&os_scsi_tapes_lock); write_unlock(&os_scsi_tapes_lock);
...@@ -4589,9 +4589,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4589,9 +4589,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
normalize_buffer(STp->buffer); normalize_buffer(STp->buffer);
STp->header_ok = 0; STp->header_ok = 0;
STp->in_use = 0; STp->in_use = 0;
STp->device->access_count--; scsi_device_put(STp->device);
module_put(STp->device->host->hostt->module);
return retval; return retval;
} }
...@@ -4719,9 +4717,8 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -4719,9 +4717,8 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
write_lock(&os_scsi_tapes_lock); write_lock(&os_scsi_tapes_lock);
STp->in_use = 0; STp->in_use = 0;
write_unlock(&os_scsi_tapes_lock); write_unlock(&os_scsi_tapes_lock);
STp->device->access_count--;
module_put(STp->device->host->hostt->module); scsi_device_put(STp->device);
return result; return result;
} }
......
...@@ -1877,20 +1877,12 @@ int scsi_attach_device(struct scsi_device *sdev) ...@@ -1877,20 +1877,12 @@ int scsi_attach_device(struct scsi_device *sdev)
struct Scsi_Device_Template *sdt; struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex); down_read(&scsi_devicelist_mutex);
list_for_each_entry(sdt, &scsi_devicelist, list) list_for_each_entry(sdt, &scsi_devicelist, list) {
if (sdt->attach) { if (!try_module_get(sdt->module))
/* continue;
* XXX check result when the upper level attach (*sdt->attach)(sdev);
* return values are fixed, and on failure goto module_put(sdt->module);
* fail. }
*/
if(try_module_get(sdt->module)) {
(*sdt->attach)(sdev);
module_put(sdt->module);
} else {
printk(KERN_WARNING "SCSI module %s not ready, skipping attach.\n", sdt->name);
}
}
up_read(&scsi_devicelist_mutex); up_read(&scsi_devicelist_mutex);
return 0; return 0;
} }
...@@ -1900,18 +1892,30 @@ void scsi_detach_device(struct scsi_device *sdev) ...@@ -1900,18 +1892,30 @@ void scsi_detach_device(struct scsi_device *sdev)
struct Scsi_Device_Template *sdt; struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex); down_read(&scsi_devicelist_mutex);
list_for_each_entry(sdt, &scsi_devicelist, list) list_for_each_entry(sdt, &scsi_devicelist, list) {
if (sdt->detach) { if (!try_module_get(sdt->module))
if(try_module_get(sdt->module)) { continue;
(*sdt->detach)(sdev); (*sdt->detach)(sdev);
module_put(sdt->module); module_put(sdt->module);
} else { }
printk(KERN_WARNING "SCSI module %s not ready, skipping detach.\n", sdt->name);
}
}
up_read(&scsi_devicelist_mutex); up_read(&scsi_devicelist_mutex);
} }
int scsi_device_get(struct scsi_device *sdev)
{
if (!try_module_get(sdev->host->hostt->module))
return -ENXIO;
sdev->access_count++;
return 0;
}
void scsi_device_put(struct scsi_device *sdev)
{
sdev->access_count--;
module_put(sdev->host->hostt->module);
}
/* /*
* Function: scsi_slave_attach() * Function: scsi_slave_attach()
* *
...@@ -1935,7 +1939,7 @@ int scsi_slave_attach(struct scsi_device *sdev) ...@@ -1935,7 +1939,7 @@ int scsi_slave_attach(struct scsi_device *sdev)
printk(KERN_ERR "scsi: Allocation failure during" printk(KERN_ERR "scsi: Allocation failure during"
" attach, some SCSI devices might not be" " attach, some SCSI devices might not be"
" configured\n"); " configured\n");
return 1; return -ENOMEM;
} }
if (sdev->host->hostt->slave_configure != NULL) { if (sdev->host->hostt->slave_configure != NULL) {
if (sdev->host->hostt->slave_configure(sdev) != 0) { if (sdev->host->hostt->slave_configure(sdev) != 0) {
...@@ -1943,7 +1947,7 @@ int scsi_slave_attach(struct scsi_device *sdev) ...@@ -1943,7 +1947,7 @@ int scsi_slave_attach(struct scsi_device *sdev)
" attach, some SCSI device might not be" " attach, some SCSI device might not be"
" configured\n"); " configured\n");
scsi_release_commandblocks(sdev); scsi_release_commandblocks(sdev);
return 1; return -ENOMEM;
} }
} else if (sdev->host->cmd_per_lun != 0) } else if (sdev->host->cmd_per_lun != 0)
scsi_adjust_queue_depth(sdev, 0, scsi_adjust_queue_depth(sdev, 0,
......
...@@ -448,8 +448,10 @@ extern void scsi_release_commandblocks(Scsi_Device * SDpnt); ...@@ -448,8 +448,10 @@ extern void scsi_release_commandblocks(Scsi_Device * SDpnt);
extern void scsi_build_commandblocks(Scsi_Device * SDpnt); extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
extern void scsi_adjust_queue_depth(Scsi_Device *, int, int); extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
extern int scsi_track_queue_full(Scsi_Device *, int); extern int scsi_track_queue_full(Scsi_Device *, int);
extern int scsi_slave_attach(struct scsi_device *sdev); extern int scsi_slave_attach(struct scsi_device *);
extern void scsi_slave_detach(struct scsi_device *sdev); extern void scsi_slave_detach(struct scsi_device *);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
extern void scsi_done(Scsi_Cmnd * SCpnt); extern void scsi_done(Scsi_Cmnd * SCpnt);
extern void scsi_finish_command(Scsi_Cmnd *); extern void scsi_finish_command(Scsi_Cmnd *);
extern int scsi_retry_command(Scsi_Cmnd *); extern int scsi_retry_command(Scsi_Cmnd *);
......
...@@ -1340,7 +1340,7 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1340,7 +1340,7 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
return SCSI_SCAN_LUN_PRESENT; return SCSI_SCAN_LUN_PRESENT;
} }
static int scsi_remove_lun(struct scsi_device *sdev) static void scsi_remove_lun(struct scsi_device *sdev)
{ {
devfs_unregister(sdev->de); devfs_unregister(sdev->de);
scsi_device_unregister(sdev); scsi_device_unregister(sdev);
......
...@@ -81,6 +81,8 @@ EXPORT_SYMBOL(scsi_register_blocked_host); ...@@ -81,6 +81,8 @@ EXPORT_SYMBOL(scsi_register_blocked_host);
EXPORT_SYMBOL(scsi_deregister_blocked_host); EXPORT_SYMBOL(scsi_deregister_blocked_host);
EXPORT_SYMBOL(scsi_slave_attach); EXPORT_SYMBOL(scsi_slave_attach);
EXPORT_SYMBOL(scsi_slave_detach); EXPORT_SYMBOL(scsi_slave_detach);
EXPORT_SYMBOL(scsi_device_get);
EXPORT_SYMBOL(scsi_device_put);
/* /*
* This symbol is for the highlevel drivers (e.g. sg) only. * This symbol is for the highlevel drivers (e.g. sg) only.
......
...@@ -261,9 +261,9 @@ sg_open(struct inode *inode, struct file *filp) ...@@ -261,9 +261,9 @@ sg_open(struct inode *inode, struct file *filp)
/* This driver's module count bumped by fops_get in <linux/fs.h> */ /* This driver's module count bumped by fops_get in <linux/fs.h> */
/* Prevent the device driver from vanishing while we sleep */ /* Prevent the device driver from vanishing while we sleep */
if (!try_module_get(sdp->device->host->hostt->module)) retval = scsi_device_get(sdp->device);
return -ENXIO; if (retval)
sdp->device->access_count++; return retval;
if (!((flags & O_NONBLOCK) || if (!((flags & O_NONBLOCK) ||
scsi_block_when_processing_errors(sdp->device))) { scsi_block_when_processing_errors(sdp->device))) {
...@@ -316,8 +316,7 @@ sg_open(struct inode *inode, struct file *filp) ...@@ -316,8 +316,7 @@ sg_open(struct inode *inode, struct file *filp)
return 0; return 0;
error_out: error_out:
sdp->device->access_count--; scsi_device_put(sdp->device);
module_put(sdp->device->host->hostt->module);
return retval; return retval;
} }
...@@ -334,8 +333,7 @@ sg_release(struct inode *inode, struct file *filp) ...@@ -334,8 +333,7 @@ sg_release(struct inode *inode, struct file *filp)
sg_fasync(-1, filp, 0); /* remove filp from async notification list */ sg_fasync(-1, filp, 0); /* remove filp from async notification list */
if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */ if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
if (!sdp->detached) { if (!sdp->detached) {
sdp->device->access_count--; scsi_device_put(sdp->device);
module_put(sdp->device->host->hostt->module);
} }
sdp->exclude = 0; sdp->exclude = 0;
wake_up_interruptible(&sdp->o_excl_wait); wake_up_interruptible(&sdp->o_excl_wait);
...@@ -1298,8 +1296,7 @@ sg_cmd_done(Scsi_Cmnd * SCpnt) ...@@ -1298,8 +1296,7 @@ sg_cmd_done(Scsi_Cmnd * SCpnt)
if (NULL == sfp->headrp) { if (NULL == sfp->headrp) {
SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n"));
if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
sdp->device->access_count--; scsi_device_put(sdp->device);
module_put(sdp->device->host->hostt->module);
} }
sfp = NULL; sfp = NULL;
} }
...@@ -1374,15 +1371,19 @@ static DEVICE_ATTR(type,S_IRUGO,sg_device_type_read,NULL); ...@@ -1374,15 +1371,19 @@ static DEVICE_ATTR(type,S_IRUGO,sg_device_type_read,NULL);
static int static int
sg_attach(Scsi_Device * scsidp) sg_attach(Scsi_Device * scsidp)
{ {
struct gendisk *disk = alloc_disk(1); struct gendisk *disk;
Sg_device *sdp = NULL; Sg_device *sdp = NULL;
unsigned long iflags; unsigned long iflags;
int k; int k, error;
disk = alloc_disk(1);
if (!disk) if (!disk)
return 1; return -ENOMEM;
if (scsi_slave_attach(scsidp))
return 1; error = scsi_slave_attach(scsidp);
if (error)
goto out_put;
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
if (sg_nr_dev >= sg_dev_max) { /* try to resize */ if (sg_nr_dev >= sg_dev_max) { /* try to resize */
Sg_device **tmp_da; Sg_device **tmp_da;
...@@ -1394,9 +1395,8 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1394,9 +1395,8 @@ sg_attach(Scsi_Device * scsidp)
if (NULL == tmp_da) { if (NULL == tmp_da) {
printk(KERN_ERR printk(KERN_ERR
"sg_attach: device array cannot be resized\n"); "sg_attach: device array cannot be resized\n");
put_disk(disk); error = -ENOMEM;
scsi_slave_detach(scsidp); goto out_detach;
return 1;
} }
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *)); memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
...@@ -1420,9 +1420,8 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1420,9 +1420,8 @@ sg_attach(Scsi_Device * scsidp)
scsidp->lun, scsidp->type, SG_MAX_DEVS_MASK); scsidp->lun, scsidp->type, SG_MAX_DEVS_MASK);
if (NULL != sdp) if (NULL != sdp)
vfree((char *) sdp); vfree((char *) sdp);
put_disk(disk); error = -ENODEV;
scsi_slave_detach(scsidp); goto out_detach;
return 1;
} }
if (k < sg_dev_max) { if (k < sg_dev_max) {
if (NULL == sdp) { if (NULL == sdp) {
...@@ -1437,9 +1436,8 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1437,9 +1436,8 @@ sg_attach(Scsi_Device * scsidp)
if (NULL == sdp) { if (NULL == sdp) {
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n"); printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
put_disk(disk); error = -ENOMEM;
scsi_slave_detach(scsidp); goto out_detach;
return 1;
} }
SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
...@@ -1492,6 +1490,12 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1492,6 +1490,12 @@ sg_attach(Scsi_Device * scsidp)
scsidp->lun, scsidp->type); scsidp->lun, scsidp->type);
} }
return 0; return 0;
out_detach:
scsi_slave_detach(scsidp);
out_put:
put_disk(disk);
return error;
} }
static void static void
...@@ -1523,8 +1527,7 @@ sg_detach(Scsi_Device * scsidp) ...@@ -1523,8 +1527,7 @@ sg_detach(Scsi_Device * scsidp)
sg_finish_rem_req(srp); sg_finish_rem_req(srp);
} }
if (sfp->closed) { if (sfp->closed) {
sdp->device->access_count--; scsi_device_put(sdp->device);
module_put(sdp->device->host->hostt->module);
__sg_remove_sfp(sdp, sfp); __sg_remove_sfp(sdp, sfp);
} else { } else {
delay = 1; delay = 1;
...@@ -2512,8 +2515,7 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) ...@@ -2512,8 +2515,7 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
/* MOD_INC's to inhibit unloading sg and associated adapter driver */ /* MOD_INC's to inhibit unloading sg and associated adapter driver */
/* only bump the access_count if we actually succeeded in /* only bump the access_count if we actually succeeded in
* throwing another counter on the host module */ * throwing another counter on the host module */
if(try_module_get(sdp->device->host->hostt->module)) scsi_device_get(sdp->device); /* XXX: retval ignored? */
sdp->device->access_count++;
sfp->closed = 1; /* flag dirty state on this fd */ sfp->closed = 1; /* flag dirty state on this fd */
SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n", SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n",
dirty)); dirty));
......
...@@ -87,6 +87,8 @@ static LIST_HEAD(sr_devlist); ...@@ -87,6 +87,8 @@ static LIST_HEAD(sr_devlist);
static spinlock_t sr_devlist_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sr_devlist_lock = SPIN_LOCK_UNLOCKED;
static int sr_open(struct cdrom_device_info *, int); static int sr_open(struct cdrom_device_info *, int);
static void sr_release(struct cdrom_device_info *);
static void get_sectorsize(struct scsi_cd *); static void get_sectorsize(struct scsi_cd *);
static void get_capabilities(struct scsi_cd *); static void get_capabilities(struct scsi_cd *);
...@@ -124,16 +126,6 @@ static inline void sr_devlist_remove(Scsi_CD *cd) ...@@ -124,16 +126,6 @@ static inline void sr_devlist_remove(Scsi_CD *cd)
spin_unlock(&sr_devlist_lock); spin_unlock(&sr_devlist_lock);
} }
static void sr_release(struct cdrom_device_info *cdi)
{
struct scsi_cd *cd = cdi->handle;
if (cd->device->sector_size > 2048)
sr_set_blocklength(cd, 2048);
cd->device->access_count--;
module_put(cd->device->host->hostt->module);
}
static struct cdrom_device_ops sr_dops = { static struct cdrom_device_ops sr_dops = {
.open = sr_open, .open = sr_open,
.release = sr_release, .release = sr_release,
...@@ -460,43 +452,59 @@ struct block_device_operations sr_bdops = ...@@ -460,43 +452,59 @@ struct block_device_operations sr_bdops =
static int sr_open(struct cdrom_device_info *cdi, int purpose) static int sr_open(struct cdrom_device_info *cdi, int purpose)
{ {
struct scsi_cd *cd = cdi->handle; struct scsi_cd *cd = cdi->handle;
struct scsi_device *sdev = cd->device;
int retval;
if (!cd->device) retval = scsi_device_get(sdev);
return -ENXIO; /* No such device */ if (retval)
return retval;
/* /*
* 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.
*/ */
if (!scsi_block_when_processing_errors(cd->device)) { retval = -ENXIO;
return -ENXIO; if (!scsi_block_when_processing_errors(sdev))
} goto error_out;
if(!try_module_get(cd->device->host->hostt->module))
return -ENXIO;
cd->device->access_count++;
/* If this device did not have media in the drive at boot time, then /*
* If this device did not have media in the drive at boot time, then
* we would have been unable to get the sector size. Check to see if * we would have been unable to get the sector size. Check to see if
* this is the case, and try again. * this is the case, and try again.
*/ */
if (cd->needs_sector_size) if (cd->needs_sector_size)
get_sectorsize(cd); get_sectorsize(cd);
return 0; return 0;
error_out:
scsi_device_put(sdev);
return retval;
}
static void sr_release(struct cdrom_device_info *cdi)
{
struct scsi_cd *cd = cdi->handle;
if (cd->device->sector_size > 2048)
sr_set_blocklength(cd, 2048);
scsi_device_put(cd->device);
} }
static int sr_attach(struct scsi_device *sdev) static int sr_attach(struct scsi_device *sdev)
{ {
struct gendisk *disk; struct gendisk *disk;
struct scsi_cd *cd; struct scsi_cd *cd;
int minor; int minor, error;
if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM) if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
return 1; return 1;
if (scsi_slave_attach(sdev)) error = scsi_slave_attach(sdev);
return 1; if (error)
return error;
error = -ENOMEM;
cd = kmalloc(sizeof(*cd), GFP_KERNEL); cd = kmalloc(sizeof(*cd), GFP_KERNEL);
if (!cd) if (!cd)
goto fail; goto fail;
...@@ -566,7 +574,7 @@ static int sr_attach(struct scsi_device *sdev) ...@@ -566,7 +574,7 @@ static int sr_attach(struct scsi_device *sdev)
kfree(cd); kfree(cd);
fail: fail:
scsi_slave_detach(sdev); scsi_slave_detach(sdev);
return 1; return error;
} }
......
...@@ -993,9 +993,9 @@ static int st_open(struct inode *inode, struct file *filp) ...@@ -993,9 +993,9 @@ static int st_open(struct inode *inode, struct file *filp)
DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
return (-EBUSY); return (-EBUSY);
} }
if(!try_module_get(STp->device->host->hostt->module))
if(!scsi_device_get(STp->device))
return (-ENXIO); return (-ENXIO);
STp->device->access_count++;
STp->in_use = 1; STp->in_use = 1;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0; STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0;
...@@ -1040,8 +1040,7 @@ static int st_open(struct inode *inode, struct file *filp) ...@@ -1040,8 +1040,7 @@ static int st_open(struct inode *inode, struct file *filp)
err_out: err_out:
normalize_buffer(STp->buffer); normalize_buffer(STp->buffer);
STp->in_use = 0; STp->in_use = 0;
STp->device->access_count--; scsi_device_put(STp->device);
module_put(STp->device->host->hostt->module);
return retval; return retval;
} }
...@@ -1174,8 +1173,7 @@ static int st_release(struct inode *inode, struct file *filp) ...@@ -1174,8 +1173,7 @@ static int st_release(struct inode *inode, struct file *filp)
write_lock(&st_dev_arr_lock); write_lock(&st_dev_arr_lock);
STp->in_use = 0; STp->in_use = 0;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
STp->device->access_count--; scsi_device_put(STp->device);
module_put(STp->device->host->hostt->module);
return result; return result;
} }
......
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