Similar changes as for ide-cd.c. diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c 2005-01-21 23:41:25 +01:00 +++ b/drivers/ide/ide-tape.c 2005-01-21 23:41:25 +01:00 @@ -781,8 +781,10 @@ * driver due to an interrupt or a timer event is stored in a variable * of type idetape_tape_t, defined below. */ -typedef struct { - ide_drive_t *drive; +typedef struct ide_tape_obj { + ide_drive_t *drive; + struct kref kref; + /* * Since a typical character device operation requires more * than one packet command, we provide here enough memory @@ -1007,6 +1009,33 @@ int debug_level; } idetape_tape_t;
+static DECLARE_MUTEX(idetape_ref_sem); + +#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref) + +#define ide_tape_g(disk) ((disk)->private_data) + +static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) +{ + struct ide_tape_obj *tape = NULL; + + down(&idetape_ref_sem); + tape = ide_tape_g(disk); + if (tape) + kref_get(&tape->kref); + up(&idetape_ref_sem); + return tape; +} + +static void ide_tape_release(struct kref *); + +static void ide_tape_put(struct ide_tape_obj *tape) +{ + down(&idetape_ref_sem); + kref_put(&tape->kref, ide_tape_release); + up(&idetape_ref_sem); +} + /* * Tape door status */ @@ -4522,9 +4551,7 @@ int stage_size; struct sysinfo si; - memset(tape, 0, sizeof (idetape_tape_t)); spin_lock_init(&tape->spinlock); - drive->driver_data = tape; drive->dsc_overlap = 1; #ifdef CONFIG_BLK_DEV_IDEPCI if (HWIF(drive)->pci_dev != NULL) { @@ -4542,7 +4569,6 @@ /* Seagate Travan drives do not support DSC overlap. */ if (strstr(drive->id->model, "Seagate STT3401")) drive->dsc_overlap = 0; - tape->drive = drive; tape->minor = minor; tape->name[0] = 'h'; tape->name[1] = 't'; @@ -4636,13 +4662,25 @@ spin_unlock_irqrestore(&ide_lock, flags); DRIVER(drive)->busy = 0; (void) ide_unregister_subdriver(drive); + + ide_tape_put(tape); + + return 0; +} + +static void ide_tape_release(struct kref *kref) +{ + struct ide_tape_obj *tape = to_ide_tape(kref); + ide_drive_t *drive = tape->drive; + struct gendisk *g = drive->disk; + drive->driver_data = NULL; devfs_remove("%s/mt", drive->devfs_name); devfs_remove("%s/mtn", drive->devfs_name); - devfs_unregister_tape(drive->disk->number); - kfree (tape); - drive->disk->fops = ide_fops; - return 0; + devfs_unregister_tape(g->number); + g->private_data = NULL; + g->fops = ide_fops; + kfree(tape); } #ifdef CONFIG_PROC_FS @@ -4707,15 +4745,30 @@ static int idetape_open(struct inode *inode, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_tape_obj *tape; + ide_drive_t *drive; + + if (!(tape = ide_tape_get(disk))) + return -ENXIO; + + drive = tape->drive; + drive->usage++; + return 0; } static int idetape_release(struct inode *inode, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_tape_obj *tape = ide_tape_g(disk); + ide_drive_t *drive = tape->drive; + drive->usage--; + + ide_tape_put(tape); + return 0; } @@ -4723,7 +4776,8 @@ unsigned int cmd, unsigned long arg) { struct block_device *bdev = inode->i_bdev; - ide_drive_t *drive = bdev->bd_disk->private_data; + struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk); + ide_drive_t *drive = tape->drive; int err = generic_ide_ioctl(drive, file, bdev, cmd, arg); if (err == -EINVAL) err = idetape_blkdev_ioctl(drive, cmd, arg); @@ -4740,6 +4794,7 @@ static int idetape_attach (ide_drive_t *drive) { idetape_tape_t *tape; + struct gendisk *g = drive->disk; int minor; if (!strstr("ide-tape", drive->driver_req)) @@ -4772,6 +4827,15 @@ } for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++) ; + + memset(tape, 0, sizeof(*tape)); + + kref_init(&tape->kref); + + tape->drive = drive; + + drive->driver_data = tape; + idetape_setup(drive, tape, minor); idetape_chrdevs[minor].drive = drive; @@ -4782,8 +4846,10 @@ S_IFCHR | S_IRUGO | S_IWUGO, "%s/mtn", drive->devfs_name); - drive->disk->number = devfs_register_tape(drive->devfs_name); - drive->disk->fops = &idetape_block_ops; + g->number = devfs_register_tape(drive->devfs_name); + g->fops = &idetape_block_ops; + g->private_data = tape; + return 0; failed: return 1; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/