[patch 5/8] ide-disk: add basic refcounting

From: Bartlomiej Zolnierkiewicz
Date: Fri Jan 21 2005 - 19:51:07 EST



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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/