Use the autoclose function provided by cdrom driver to wait for drive to close in open_finish, and attempt to open once more after the door closes. Signed-off-by: Michal Suchanek <msuchanek@xxxxxxx> --- v3: use function call rather than IOCTL v4: fix reference leak on -ENXIO --- drivers/scsi/sr.c | 54 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 07c319494bf4..41ddf08b4c7b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -522,29 +522,58 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) return ret; } -static int sr_block_open(struct block_device *bdev, fmode_t mode) +static int __sr_block_open(struct block_device *bdev, fmode_t mode) { - struct scsi_cd *cd; - struct scsi_device *sdev; - int ret = -ENXIO; - - cd = scsi_cd_get(bdev->bd_disk); - if (!cd) - goto out; + struct scsi_cd *cd = scsi_cd(bdev->bd_disk); + int ret; - sdev = cd->device; - scsi_autopm_get_device(sdev); check_disk_change(bdev); mutex_lock(&sr_mutex); ret = cdrom_open(&cd->cdi, bdev, mode); mutex_unlock(&sr_mutex); + return ret; +} + +static int sr_block_open(struct block_device *bdev, fmode_t mode) +{ + struct scsi_cd *cd = scsi_cd_get(bdev->bd_disk); + struct scsi_device *sdev; + int ret; + + if (!cd) + return -ENXIO; + + sdev = cd->device; + scsi_autopm_get_device(sdev); + ret = __sr_block_open(bdev, mode); scsi_autopm_put_device(sdev); - if (ret) + + if ((ret == -ERESTARTSYS) || (ret == -ENXIO)) scsi_cd_put(cd); -out: + return ret; +} + +static int sr_block_open_finish(struct block_device *bdev, fmode_t mode, + int ret) +{ + struct scsi_cd *cd = scsi_cd(bdev->bd_disk); + + /* wait for drive to get ready */ + if ((ret == -ENOMEDIUM) && !(mode & FMODE_NDELAY)) { + struct scsi_device *sdev = cd->device; + /* + * Cannot use sr_block_ioctl because it locks sr_mutex blocking + * out any processes trying to access the drive + */ + scsi_autopm_get_device(sdev); + cdrom_autoclose(&cd->cdi); + ret = __sr_block_open(bdev, mode); + scsi_autopm_put_device(sdev); + } + return ret; } @@ -640,6 +669,7 @@ static const struct block_device_operations sr_bdops = { .owner = THIS_MODULE, .open = sr_block_open, + .open_finish = sr_block_open_finish, .release = sr_block_release, .ioctl = sr_block_ioctl, .check_events = sr_block_check_events, -- 2.23.0