patch-2.2.11 linux/drivers/block/ide-tape.c
Next file: linux/drivers/block/ide.c
Previous file: linux/drivers/block/ide-pmac.c
Back to the patch index
Back to the overall index
- Lines: 186
- Date:
Mon Aug 9 12:04:39 1999
- Orig file:
v2.2.10/linux/drivers/block/ide-tape.c
- Orig date:
Fri Jan 8 10:04:58 1999
diff -u --recursive --new-file v2.2.10/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.14 Dec 30, 1998
+ * linux/drivers/block/ide-tape.c Version 1.15 Jul 4, 1999
*
- * Copyright (C) 1995 - 1998 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
*
* This driver was constructed as a student project in the software laboratory
* of the faculty of electrical engineering in the Technion - Israel's
@@ -214,6 +214,9 @@
* Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB
* Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives.
* Replace cli()/sti() with hwgroup spinlocks.
+ * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup
+ * spinlock with private per-tape spinlock.
+ * Fix use of freed memory.
*
* Here are some words from the first releases of hd.c, which are quoted
* in ide.c and apply here as well:
@@ -693,6 +696,7 @@
int excess_bh_size; /* Wasted space in each stage */
unsigned int flags; /* Status/Action flags */
+ spinlock_t spinlock; /* protects the ide-tape queue */
} idetape_tape_t;
/*
@@ -1439,7 +1443,7 @@
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "Reached idetape_add_stage_tail\n");
#endif /* IDETAPE_DEBUG_LOG */
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
stage->next=NULL;
if (tape->last_stage != NULL)
tape->last_stage->next=stage;
@@ -1450,7 +1454,7 @@
tape->next_stage=tape->last_stage;
tape->nr_stages++;
tape->nr_pending_stages++;
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
}
/*
@@ -1552,7 +1556,9 @@
ide_drive_t *drive = hwgroup->drive;
struct request *rq = hwgroup->rq;
idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
int error;
+ int remove_stage = 0;
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "Reached idetape_end_request\n");
@@ -1567,6 +1573,7 @@
if (error)
tape->failed_pc = NULL;
+ spin_lock_irqsave(&tape->spinlock, flags);
if (tape->active_data_request == rq) { /* The request was a pipelined data transfer request */
tape->active_stage = NULL;
tape->active_data_request = NULL;
@@ -1577,7 +1584,7 @@
if (error == IDETAPE_ERROR_EOD)
idetape_abort_pipeline (drive);
}
- idetape_remove_stage_head (drive);
+ remove_stage = 1;
}
if (tape->next_stage != NULL) {
idetape_active_next_stage (drive);
@@ -1595,6 +1602,9 @@
idetape_increase_max_pipeline_stages (drive);
}
ide_end_drive_cmd (drive, 0, 0);
+ if (remove_stage)
+ idetape_remove_stage_head (drive);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
}
/*
@@ -2335,6 +2345,7 @@
static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
{
struct semaphore sem = MUTEX_LOCKED;
+ idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_BUGS
if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
@@ -2343,9 +2354,9 @@
}
#endif /* IDETAPE_DEBUG_BUGS */
rq->sem = &sem;
- spin_unlock(&HWGROUP(drive)->spinlock);
+ spin_unlock(&tape->spinlock);
down(&sem);
- spin_lock_irq(&HWGROUP(drive)->spinlock);
+ spin_lock_irq(&tape->spinlock);
}
/*
@@ -2419,10 +2430,10 @@
*/
return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh));
}
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
if (tape->active_stage == tape->first_stage)
idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
rq_ptr = &tape->first_stage->rq;
bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -2471,12 +2482,12 @@
* Pay special attention to possible race conditions.
*/
while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
if (idetape_pipeline_active (tape)) {
idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
} else {
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
idetape_insert_pipeline_into_queue (drive);
if (idetape_pipeline_active (tape))
continue;
@@ -2533,11 +2544,11 @@
if (tape->first_stage == NULL)
return;
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
tape->next_stage = NULL;
if (idetape_pipeline_active (tape))
idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
while (tape->first_stage != NULL)
idetape_remove_stage_head (drive);
@@ -2557,7 +2568,7 @@
if (!idetape_pipeline_active (tape))
idetape_insert_pipeline_into_queue (drive);
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
if (!idetape_pipeline_active (tape))
goto abort;
#if IDETAPE_DEBUG_BUGS
@@ -2567,7 +2578,7 @@
#endif /* IDETAPE_DEBUG_BUGS */
idetape_wait_for_request(drive, &tape->last_stage->rq);
abort:
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
}
static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
@@ -2812,10 +2823,10 @@
* Wait until the first read-ahead request
* is serviced.
*/
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
if (tape->active_stage == tape->first_stage)
idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
count++;
@@ -3559,6 +3570,8 @@
u16 speed;
struct idetape_id_gcw gcw;
+ memset (tape, 0, sizeof (idetape_tape_t));
+ tape->spinlock = (spinlock_t)SPIN_LOCK_UNLOCKED;
drive->driver_data = tape;
drive->ready_stat = 0; /* An ATAPI device ignores DRDY */
drive->dsc_overlap = 1;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)