Similar changes as for ide-cd.c (except that struct ide_disk_obj is added).
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c 2005-01-21 23:41:03 +01:00 +++ b/drivers/ide/ide-disk.c 2005-01-21 23:41:03 +01:00 @@ -71,6 +71,38 @@ #include <asm/io.h> #include <asm/div64.h> +struct ide_disk_obj { + ide_drive_t *drive; + struct kref kref; +}; + +static DECLARE_MUTEX(idedisk_ref_sem); + +#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref) + +#define ide_disk_g(disk) ((disk)->private_data) + +static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) +{ + struct ide_disk_obj *idkp = NULL; + + down(&idedisk_ref_sem); + idkp = ide_disk_g(disk); + if (idkp) + kref_get(&idkp->kref); + up(&idedisk_ref_sem); + return idkp; +} + +static void ide_disk_release(struct kref *); + +static void ide_disk_put(struct ide_disk_obj *idkp) +{ + down(&idedisk_ref_sem); + kref_put(&idkp->kref, ide_disk_release); + up(&idedisk_ref_sem); +} + /* * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" * value for this drive (from its reported identification information). @@ -941,14 +973,30 @@ static int idedisk_cleanup (ide_drive_t *drive) { + struct ide_disk_obj *idkp = drive->driver_data; struct gendisk *g = drive->disk; + ide_cacheflush_p(drive); if (ide_unregister_subdriver(drive)) return 1; del_gendisk(g); + + ide_disk_put(idkp); + + return 0; +} + +static void ide_disk_release(struct kref *kref) +{ + struct ide_disk_obj *idkp = to_ide_disk(kref); + ide_drive_t *drive = idkp->drive; + struct gendisk *g = drive->disk; + + drive->driver_data = NULL; drive->devfs_name[0] = '\0'; + g->private_data = NULL; g->fops = ide_fops; - return 0; + kfree(idkp); } static int idedisk_attach(ide_drive_t *drive); @@ -1006,7 +1054,15 @@ static int idedisk_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_disk_obj *idkp; + ide_drive_t *drive; + + if (!(idkp = ide_disk_get(disk))) + return -ENXIO; + + drive = idkp->drive; + drive->usage++; if (drive->removable && drive->usage == 1) { ide_task_t args; @@ -1028,7 +1084,10 @@ static int idedisk_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_disk_obj *idkp = ide_disk_g(disk); + ide_drive_t *drive = idkp->drive; + if (drive->usage == 1) ide_cacheflush_p(drive); if (drive->removable && drive->usage == 1) { @@ -1041,6 +1100,9 @@ drive->doorlocking = 0; } drive->usage--; + + ide_disk_put(idkp); + return 0; } @@ -1048,13 +1110,14 @@ unsigned int cmd, unsigned long arg) { struct block_device *bdev = inode->i_bdev; - ide_drive_t *drive = bdev->bd_disk->private_data; - return generic_ide_ioctl(drive, file, bdev, cmd, arg); + struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); + return generic_ide_ioctl(idkp->drive, file, bdev, cmd, arg); } static int idedisk_media_changed(struct gendisk *disk) { - ide_drive_t *drive = disk->private_data; + struct ide_disk_obj *idkp = ide_disk_g(disk); + ide_drive_t *drive = idkp->drive; /* do not scan partitions twice if this is a removable device */ if (drive->attach) { @@ -1067,8 +1130,8 @@ static int idedisk_revalidate_disk(struct gendisk *disk) { - ide_drive_t *drive = disk->private_data; - set_capacity(disk, idedisk_capacity(drive)); + struct ide_disk_obj *idkp = ide_disk_g(disk); + set_capacity(disk, idedisk_capacity(idkp->drive)); return 0; } @@ -1085,6 +1148,7 @@ static int idedisk_attach(ide_drive_t *drive) { + struct ide_disk_obj *idkp; struct gendisk *g = drive->disk; /* strstr("foo", "") is non-NULL */ @@ -1095,10 +1159,22 @@ if (drive->media != ide_disk) goto failed; + idkp = kmalloc(sizeof(*idkp), GFP_KERNEL); + if (!idkp) + goto failed; + if (ide_register_subdriver(drive, &idedisk_driver)) { printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); - goto failed; + goto out_free_idkp; } + + memset(idkp, 0, sizeof(*idkp)); + + kref_init(&idkp->kref); + + idkp->drive = drive; + drive->driver_data = idkp; + DRIVER(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { @@ -1114,8 +1190,11 @@ g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; set_capacity(g, idedisk_capacity(drive)); g->fops = &idedisk_ops; + g->private_data = idkp; add_disk(g); return 0; +out_free_idkp: + kfree(idkp); 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/