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/

Reply via email to