Commit 8fc7b528 authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz Committed by Linus Torvalds

[PATCH] ide: fix ide_unregister() vs. driver model

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

This patch seem to have been lost, so here it is again.  It fixes an Ooops
on unregistering hwifs due to the device model now having mandatory
release() functions.  It also close the possible race we had on release if
the entry was in use (by or /sys typically) by using a semaphore waiting
for the release() to be called after doing an unregister.
parent ed2149ac
...@@ -644,6 +644,13 @@ static inline u8 probe_for_drive (ide_drive_t *drive) ...@@ -644,6 +644,13 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
return drive->present; return drive->present;
} }
static void hwif_release_dev (struct device *dev)
{
ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
up(&hwif->gendev_rel_sem);
}
static void hwif_register (ide_hwif_t *hwif) static void hwif_register (ide_hwif_t *hwif)
{ {
/* register with global device tree */ /* register with global device tree */
...@@ -656,6 +663,7 @@ static void hwif_register (ide_hwif_t *hwif) ...@@ -656,6 +663,7 @@ static void hwif_register (ide_hwif_t *hwif)
/* Would like to do = &device_legacy */ /* Would like to do = &device_legacy */
hwif->gendev.parent = NULL; hwif->gendev.parent = NULL;
} }
hwif->gendev.release = hwif_release_dev;
device_register(&hwif->gendev); device_register(&hwif->gendev);
} }
...@@ -1196,6 +1204,13 @@ static int alloc_disks(ide_hwif_t *hwif) ...@@ -1196,6 +1204,13 @@ static int alloc_disks(ide_hwif_t *hwif)
return -ENOMEM; return -ENOMEM;
} }
static void drive_release_dev (struct device *dev)
{
ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
up(&drive->gendev_rel_sem);
}
/* /*
* init_gendisk() (as opposed to ide_geninit) is called for each major device, * init_gendisk() (as opposed to ide_geninit) is called for each major device,
* after probing for drives, to allocate partition tables and other data * after probing for drives, to allocate partition tables and other data
...@@ -1214,6 +1229,7 @@ static void init_gendisk (ide_hwif_t *hwif) ...@@ -1214,6 +1229,7 @@ static void init_gendisk (ide_hwif_t *hwif)
drive->gendev.parent = &hwif->gendev; drive->gendev.parent = &hwif->gendev;
drive->gendev.bus = &ide_bus_type; drive->gendev.bus = &ide_bus_type;
drive->gendev.driver_data = drive; drive->gendev.driver_data = drive;
drive->gendev.release = drive_release_dev;
if (drive->present) { if (drive->present) {
device_register(&drive->gendev); device_register(&drive->gendev);
sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d", sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
......
...@@ -251,6 +251,8 @@ static void init_hwif_data (unsigned int index) ...@@ -251,6 +251,8 @@ static void init_hwif_data (unsigned int index)
hwif->mwdma_mask = 0x80; /* disable all mwdma */ hwif->mwdma_mask = 0x80; /* disable all mwdma */
hwif->swdma_mask = 0x80; /* disable all swdma */ hwif->swdma_mask = 0x80; /* disable all swdma */
sema_init(&hwif->gendev_rel_sem, 0);
default_hwif_iops(hwif); default_hwif_iops(hwif);
default_hwif_transport(hwif); default_hwif_transport(hwif);
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
...@@ -273,6 +275,7 @@ static void init_hwif_data (unsigned int index) ...@@ -273,6 +275,7 @@ static void init_hwif_data (unsigned int index)
drive->driver = &idedefault_driver; drive->driver = &idedefault_driver;
drive->vdma = 0; drive->vdma = 0;
INIT_LIST_HEAD(&drive->list); INIT_LIST_HEAD(&drive->list);
sema_init(&drive->gendev_rel_sem, 0);
} }
} }
...@@ -745,6 +748,7 @@ void ide_unregister (unsigned int index) ...@@ -745,6 +748,7 @@ void ide_unregister (unsigned int index)
spin_unlock_irq(&ide_lock); spin_unlock_irq(&ide_lock);
blk_cleanup_queue(drive->queue); blk_cleanup_queue(drive->queue);
device_unregister(&drive->gendev); device_unregister(&drive->gendev);
down(&drive->gendev_rel_sem);
spin_lock_irq(&ide_lock); spin_lock_irq(&ide_lock);
drive->queue = NULL; drive->queue = NULL;
} }
...@@ -774,6 +778,7 @@ void ide_unregister (unsigned int index) ...@@ -774,6 +778,7 @@ void ide_unregister (unsigned int index)
/* More messed up locking ... */ /* More messed up locking ... */
spin_unlock_irq(&ide_lock); spin_unlock_irq(&ide_lock);
device_unregister(&hwif->gendev); device_unregister(&hwif->gendev);
down(&hwif->gendev_rel_sem);
/* /*
* Remove us from the kernel's knowledge * Remove us from the kernel's knowledge
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/hdreg.h> #include <asm/hdreg.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/semaphore.h>
#define DEBUG_PM #define DEBUG_PM
...@@ -774,6 +775,7 @@ typedef struct ide_drive_s { ...@@ -774,6 +775,7 @@ typedef struct ide_drive_s {
int crc_count; /* crc counter to reduce drive speed */ int crc_count; /* crc counter to reduce drive speed */
struct list_head list; struct list_head list;
struct device gendev; struct device gendev;
struct semaphore gendev_rel_sem; /* to deal with device release() */
struct gendisk *disk; struct gendisk *disk;
} ide_drive_t; } ide_drive_t;
...@@ -1040,6 +1042,7 @@ typedef struct hwif_s { ...@@ -1040,6 +1042,7 @@ typedef struct hwif_s {
unsigned auto_poll : 1; /* supports nop auto-poll */ unsigned auto_poll : 1; /* supports nop auto-poll */
struct device gendev; struct device gendev;
struct semaphore gendev_rel_sem; /* To deal with device release() */
void *hwif_data; /* extra hwif data */ void *hwif_data; /* extra hwif data */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment