Am Freitag, 13. Januar 2012, 17:20:10 schrieb Alan Stern: > > 2. scsi_autopm_get_device(sdev) is called unconditionally on each open. > > But according to the comment on the top of sd_release(). scsi_autopm_put_device(sdev) > > would be called only for the last close. Doesn't that mean that concurrent > > open calls for a disk disable autosuspend permanently? > > There ought to be an analogous comment for sd_open() -- it gets called > only for the first open. > > This means something different from what you're probably thinking. If > two separate systems calls to open(2) are made (either in the same > process or in different processes), followed by two calls to close(2), > then sd_open and sd_release will each be invoked twice. > > However, if open(2) is called once followed by dup(2), and close(2) is > called twice (for both the original fd and the fd returned by dup), > then sd_open and sd_release will both be invoked only once. Even > though there are two file descriptors, there's only one open file > reference. > > BTW, there's one other thing you need to know -- an error in your > patch. SCSI doesn't use the same scheme as USB for indicating whether > a driver supports autosuspend. Instead it uses PCI's scheme: > Thanks, that clears up everything. Sarah, here's a correct patch for testing. Regards Oliver >From 4ebcfed1056f0c9e974c4cf5e92e8cb77a627046 Mon Sep 17 00:00:00 2001 From: Oliver Neukum <oliver@xxxxxxxxxx> Date: Sat, 14 Jan 2012 23:45:55 +0100 Subject: [PATCH] SCSI:implement PM for sr This implements basic power management for SCSI disks. Signed-off-by: Oliver Neukum <oneukum@xxxxxxx> --- drivers/scsi/sr.c | 31 +++++++++++++++++++++++++++++-- 1 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 5fc97d2..91b545b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -508,16 +508,29 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) static int sr_block_open(struct block_device *bdev, fmode_t mode) { + struct scsi_device *sdev; struct scsi_cd *cd; int ret = -ENXIO; + int err; mutex_lock(&sr_mutex); cd = scsi_cd_get(bdev->bd_disk); + sdev = cd->device; + + err = scsi_autopm_get_device(sdev); + if (err) { + ret = -EIO; + goto err_out; + } + if (cd) { ret = cdrom_open(&cd->cdi, bdev, mode); - if (ret) + if (ret) { scsi_cd_put(cd); + scsi_autopm_put_device(sdev); + } } +err_out: mutex_unlock(&sr_mutex); return ret; } @@ -525,9 +538,12 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) static int sr_block_release(struct gendisk *disk, fmode_t mode) { struct scsi_cd *cd = scsi_cd(disk); + struct scsi_device *sdev = cd->device; + mutex_lock(&sr_mutex); cdrom_release(&cd->cdi, mode); scsi_cd_put(cd); + scsi_autopm_put_device(sdev); mutex_unlock(&sr_mutex); return 0; } @@ -615,6 +631,11 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose) struct scsi_device *sdev = cd->device; int retval; + retval = scsi_autopm_get_device(sdev); + if (retval) { + retval = -EIO; + goto pm_error_out; + } /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. @@ -626,16 +647,19 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose) return 0; error_out: + scsi_autopm_put_device(sdev); +pm_error_out: return retval; } static void sr_release(struct cdrom_device_info *cdi) { struct scsi_cd *cd = cdi->handle; + struct scsi_device *sdev = cd->device; if (cd->device->sector_size > 2048) sr_set_blocklength(cd, 2048); - + scsi_autopm_put_device(sdev); } static int sr_probe(struct device *dev) @@ -715,6 +739,7 @@ static int sr_probe(struct device *dev) dev_set_drvdata(dev, cd); disk->flags |= GENHD_FL_REMOVABLE; add_disk(disk); + scsi_autopm_put_device(sdev); sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name); @@ -964,7 +989,9 @@ static void sr_kref_release(struct kref *kref) static int sr_remove(struct device *dev) { struct scsi_cd *cd = dev_get_drvdata(dev); + struct scsi_device *sdev = cd->device; + scsi_autopm_get_device(sdev); blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn); del_gendisk(cd->disk); -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html