ide: fix refcounting in device drivers

During host driver module removal del_gendisk() results in a final
put on drive->gendev and freeing the drive by drive_release_dev().

Convert device drivers from using struct kref to use struct device
so device driver's object holds reference on ->gendev and prevents
drive from prematurely going away.

Also fix ->remove methods to not erroneously drop reference on a
host driver by using only put_device() instead of ide*_put().

Reported-by: Stanislaw Gruszka <stf_xl@wp.pl>
Tested-by: Stanislaw Gruszka <stf_xl@wp.pl>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
Bartlomiej Zolnierkiewicz
2009-02-25 20:28:24 +01:00
parent d3dd7107f4
commit 8fed436841
6 changed files with 57 additions and 31 deletions

View File

@@ -25,7 +25,7 @@ module_param(debug_mask, ulong, 0644);
static DEFINE_MUTEX(ide_disk_ref_mutex);
static void ide_disk_release(struct kref *);
static void ide_disk_release(struct device *);
static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
{
@@ -37,7 +37,7 @@ static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
if (ide_device_get(idkp->drive))
idkp = NULL;
else
kref_get(&idkp->kref);
get_device(&idkp->dev);
}
mutex_unlock(&ide_disk_ref_mutex);
return idkp;
@@ -48,7 +48,7 @@ static void ide_disk_put(struct ide_disk_obj *idkp)
ide_drive_t *drive = idkp->drive;
mutex_lock(&ide_disk_ref_mutex);
kref_put(&idkp->kref, ide_disk_release);
put_device(&idkp->dev);
ide_device_put(drive);
mutex_unlock(&ide_disk_ref_mutex);
}
@@ -66,17 +66,18 @@ static void ide_gd_remove(ide_drive_t *drive)
struct gendisk *g = idkp->disk;
ide_proc_unregister_driver(drive, idkp->driver);
device_del(&idkp->dev);
del_gendisk(g);
drive->disk_ops->flush(drive);
ide_disk_put(idkp);
mutex_lock(&ide_disk_ref_mutex);
put_device(&idkp->dev);
mutex_unlock(&ide_disk_ref_mutex);
}
static void ide_disk_release(struct kref *kref)
static void ide_disk_release(struct device *dev)
{
struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
ide_drive_t *drive = idkp->drive;
struct gendisk *g = idkp->disk;
@@ -348,7 +349,12 @@ static int ide_gd_probe(ide_drive_t *drive)
ide_init_disk(g, drive);
kref_init(&idkp->kref);
idkp->dev.parent = &drive->gendev;
idkp->dev.release = ide_disk_release;
dev_set_name(&idkp->dev, dev_name(&drive->gendev));
if (device_register(&idkp->dev))
goto out_free_disk;
idkp->drive = drive;
idkp->driver = &ide_gd_driver;
@@ -373,6 +379,8 @@ static int ide_gd_probe(ide_drive_t *drive)
add_disk(g);
return 0;
out_free_disk:
put_disk(g);
out_free_idkp:
kfree(idkp);
failed: