From: Andrew Morton ahd_linux_queue() forgets to drop the lock on an error return path. Fix that up and convert the function to single-exit so it doesn't happen again. Cc: James Bottomley Signed-off-by: Andrew Morton --- drivers/scsi/aic7xxx/aic79xx_osm.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff -puN drivers/scsi/aic7xxx/aic79xx_osm.c~aic79xx-deadlock-fix drivers/scsi/aic7xxx/aic79xx_osm.c --- 25/drivers/scsi/aic7xxx/aic79xx_osm.c~aic79xx-deadlock-fix 2005-06-18 23:17:04.000000000 -0700 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm.c 2005-06-18 23:17:04.000000000 -0700 @@ -933,6 +933,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* struct ahd_softc *ahd; struct ahd_linux_device *dev; u_long flags; + int ret = 0; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -955,8 +956,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); - ahd_unlock(ahd, &flags); - return (0); + goto out; } dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, cmd->device->lun, @@ -965,13 +965,14 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); - ahd_unlock(ahd, &flags); printf("%s: aic79xx_linux_queue - Unable to allocate device!\n", ahd_name(ahd)); - return (0); + goto out; + } + if (cmd->cmd_len > MAX_CDB_LEN) { + ret = -EINVAL; + goto out; } - if (cmd->cmd_len > MAX_CDB_LEN) - return (-EINVAL); cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe); if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { @@ -979,8 +980,9 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* dev->flags |= AHD_DEV_ON_RUN_LIST; ahd_linux_run_device_queues(ahd); } +out: ahd_unlock(ahd, &flags); - return (0); + return ret; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) _