From: Andries.Brouwer@cwi.nl A rather reproducible crash with ide-scsi that I reported yesterday is fixed by the patch below. (Most of this is just polishing that emacs did while my eyes looked at the code. The only change is not doing ide_do_drive_cmd (drive, rq, ide_end); spin_lock_irq(cmd->device->host->host_lock); since cmd may be freed already.) Andries [With this in place I wrote three times 640 MB to floptical and diffed; no problems occurred. Without it the system would crash each time.] --- drivers/ide/ide-io.c | 2 +- drivers/scsi/ide-scsi.c | 41 +++++++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff -puN drivers/ide/ide-io.c~ide-scsi-use-after-free-fix drivers/ide/ide-io.c --- 25/drivers/ide/ide-io.c~ide-scsi-use-after-free-fix 2004-01-18 21:08:12.000000000 -0800 +++ 25-akpm/drivers/ide/ide-io.c 2004-01-18 21:08:12.000000000 -0800 @@ -1300,7 +1300,7 @@ EXPORT_SYMBOL(ide_intr); * Initialize a request before we fill it in and send it down to * ide_do_drive_cmd. Commands must be set up by this function. Right * now it doesn't do a lot, but if that changes abusers will have a - * nasty suprise. + * nasty surprise. */ void ide_init_drive_cmd (struct request *rq) diff -puN drivers/scsi/ide-scsi.c~ide-scsi-use-after-free-fix drivers/scsi/ide-scsi.c --- 25/drivers/scsi/ide-scsi.c~ide-scsi-use-after-free-fix 2004-01-18 21:08:12.000000000 -0800 +++ 25-akpm/drivers/scsi/ide-scsi.c 2004-01-18 21:08:12.000000000 -0800 @@ -148,7 +148,8 @@ static void idescsi_input_buffers (ide_d count = IDE_MIN (pc->sg->length - pc->b_count, bcount); buf = page_address(pc->sg->page) + pc->sg->offset; atapi_input_bytes (drive, buf + pc->b_count, count); - bcount -= count; pc->b_count += count; + bcount -= count; + pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; pc->b_count = 0; @@ -191,8 +192,12 @@ static inline void idescsi_transform_pc1 return; if (drive->media == ide_cdrom || drive->media == ide_optical) { if (c[0] == READ_6 || c[0] == WRITE_6) { - c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; - c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; + c[8] = c[4]; + c[5] = c[3]; + c[4] = c[2]; + c[3] = c[1] & 0x1f; + c[2] = 0; + c[1] &= 0xe0; c[0] += (READ_10 - READ_6); } if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) { @@ -380,7 +385,7 @@ static inline unsigned long get_timeout( static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); - idescsi_pc_t *pc=scsi->pc; + idescsi_pc_t *pc = scsi->pc; struct request *rq = pc->rq; atapi_bcount_t bcount; atapi_status_t status; @@ -664,8 +669,6 @@ static struct block_device_operations id .ioctl = idescsi_ide_ioctl, }; -static int idescsi_attach(ide_drive_t *drive); - static int idescsi_slave_configure(Scsi_Device * sdp) { /* Configure detected device */ @@ -794,7 +797,8 @@ static int idescsi_queue (Scsi_Cmnd *cmd idescsi_pc_t *pc = NULL; if (!drive) { - printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->device->id); + printk (KERN_ERR "ide-scsi: drive id %d not present\n", + cmd->device->id); goto abort; } scsi = drive_to_idescsi(drive); @@ -827,25 +831,30 @@ static int idescsi_queue (Scsi_Cmnd *cmd idescsi_transform_pc1 (drive, pc); if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { - printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); + printk ("ide-scsi: %s: que %lu, cmd = ", + drive->name, cmd->serial_number); hexdump(cmd->cmnd, cmd->cmd_len); if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) { - printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number); + printk("ide-scsi: %s: que %lu, tsl = ", + drive->name, cmd->serial_number); hexdump(pc->c, 12); } } - ide_init_drive_cmd (rq); + ide_init_drive_cmd(rq); rq->special = (char *) pc; - rq->bio = idescsi_dma_bio (drive, pc); + rq->bio = idescsi_dma_bio(drive, pc); rq->flags = REQ_SPECIAL; - spin_unlock_irq(cmd->device->host->host_lock); - (void) ide_do_drive_cmd (drive, rq, ide_end); - spin_lock_irq(cmd->device->host->host_lock); + { + struct Scsi_Host *host = cmd->device->host; + spin_unlock_irq(host->host_lock); + (void) ide_do_drive_cmd(drive, rq, ide_end); + spin_lock_irq(host->host_lock); + } return 0; abort: - if (pc) kfree (pc); - if (rq) kfree (rq); + kfree (pc); + kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); return 1; _