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:
@@ -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:
|
||||
|
Reference in New Issue
Block a user