DORMANTno replies

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

From: Bartlomiej Zolnierkiewicz <hidden>
Date: 2005-01-22 00:43:25
Also in: lkml

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;
 }
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help