From: Alan Cox <alan@redhat.com>
To: linux-ide@vger.kernel.org, linux-kernel@vger.kernel.org,
torvalds@osdl.org
Subject: PATCH: straighten out the IDE layer locking and add hotplug
Date: Sun, 15 Aug 2004 11:13:46 -0400 [thread overview]
Message-ID: <20040815151346.GA13761@devserv.devel.redhat.com> (raw)
There really isnt any sane way to break this patch down because all the
changes are interlinked so closely.
We now
- enforce and document an actual lock order
- use a seperate semaphore to get sleep-read/spin-write locking for
the lists that need it
- Fix the driver list locking
- Fix the hwif list locking
- Remove the impossible to fix and unused stuff for passing
a device between drivers
- Change ide_unregister into ide_unregister_hwif as it now takes
a hwif pointer
- Fix various cases we wrongly dropped locks
- Split configured/present so that we can do unregister right
- Call ->remove() callbacks
This patch leaves pci and ide-cs broken, patches to move them to the new
locking follow
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.8-rc3/drivers/ide/ide.c linux-2.6.8-rc3/drivers/ide/ide.c
--- linux.vanilla-2.6.8-rc3/drivers/ide/ide.c 2004-08-09 15:51:00.000000000 +0100
+++ linux-2.6.8-rc3/drivers/ide/ide.c 2004-08-12 17:55:05.000000000 +0100
@@ -448,31 +515,46 @@
return -ENXIO;
}
+/*
+ * drives_lock protects the list of drives, drivers lock the
+ * list of drivers. Currently nobody takes both at once.
+ * drivers_sem guards the drivers_list for readers that may
+ * sleep. It must be taken before drivers_lock. Take drivers_sem
+ * before ide_setting_sem and idecfg_sem before either of the
+ * others.
+ */
+
static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(drivers_sem);
static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
+
static LIST_HEAD(drivers);
-/* Iterator */
+/* Iterator for the driver list. */
+
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct list_head *p;
loff_t l = *pos;
- spin_lock(&drivers_lock);
+ down(&drivers_sem);
list_for_each(p, &drivers)
if (!l--)
return list_entry(p, ide_driver_t, drivers);
return NULL;
}
+
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct list_head *p = ((ide_driver_t *)v)->drivers.next;
(*pos)++;
return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers);
}
+
static void m_stop(struct seq_file *m, void *v)
{
- spin_unlock(&drivers_lock);
+ up(&drivers_sem);
}
+
static int show_driver(struct seq_file *m, void *v)
{
ide_driver_t *driver = v;
@@ -515,6 +597,7 @@
* MMIO leaves it to the controller driver,
* PIO will migrate this way over time.
*/
+
int ide_hwif_request_regions(ide_hwif_t *hwif)
{
unsigned long addr;
@@ -564,6 +647,7 @@
* importantly our caller should be doing this so we need to
* restructure this as a helper function for drivers.
*/
+
void ide_hwif_release_regions(ide_hwif_t *hwif)
{
u32 i = 0;
@@ -581,7 +665,15 @@
release_region(hwif->io_ports[i], 1);
}
-/* restore hwif to a sane state */
+/**
+ * ide_hwif_restore - restore hwif to template
+ * @hwif: hwif to update
+ * @tmp_hwif: template
+ *
+ * Restore hwif to a default state by copying most settngs
+ * from the template.
+ */
+
static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
{
hwif->hwgroup = tmp_hwif->hwgroup;
@@ -678,15 +771,16 @@
}
/**
- * ide_unregister - free an ide interface
- * @index: index of interface (will change soon to a pointer)
+ * __ide_unregister_hwif - free an ide interface
+ * @hwif: interface to unregister
*
* Perform the final unregister of an IDE interface. At the moment
* we don't refcount interfaces so this will also get split up.
*
* Locking:
- * The caller must not hold the IDE locks
- * The drive present/vanishing is not yet properly locked
+ * The caller must not hold the IDE locks except for ide_cfg_sem
+ * which must be held.
+ *
* Take care with the callbacks. These have been split to avoid
* deadlocking the IDE layer. The shutdown callback is called
* before we take the lock and free resources. It is up to the
@@ -695,31 +789,43 @@
* isnt yet done btw). After we commit to the final kill we
* call the cleanup callback with the ide locks held.
*
+ * An interface can be in four states we care about
+ * - It can be busy (drive or driver thinks its active). No unload
+ * - It can be unconfigured - which means its already gone
+ * - It can be configured and present - a full interface
+ * - It can be configured and not present - pci configured but no drives
+ * so logically absent.
+ *
* Unregister restores the hwif structures to the default state.
- * This is raving bonkers.
*/
-void ide_unregister(unsigned int index)
+int __ide_unregister_hwif(ide_hwif_t *hwif)
{
ide_drive_t *drive;
- ide_hwif_t *hwif, *g, *tmp_hwif;
+ ide_hwif_t *g;
ide_hwgroup_t *hwgroup;
int irq_count = 0, unit, i;
+ int index;
+ static ide_hwif_t tmp_hwif; /* Serialized by locking */
+ int ret = 0;
+ int was_present;
- BUG_ON(index >= MAX_HWIFS);
-
- tmp_hwif = kmalloc(sizeof(*tmp_hwif), GFP_KERNEL|__GFP_NOFAIL);
- if (!tmp_hwif) {
- printk(KERN_ERR "%s: unable to allocate memory\n", __FUNCTION__);
- return;
- }
-
+ index = hwif->index;
+
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
- down(&ide_cfg_sem);
+
+ /* Make sure nobody sneaks in via the proc interface */
+ down(&ide_setting_sem);
+
+ /* Now ensure nobody gets in for I/O while we clean up and
+ do the busy check. If busy is set then the device is still
+ open and we must stop */
spin_lock_irq(&ide_lock);
- hwif = &ide_hwifs[index];
- if (!hwif->present)
+
+ printk("Unregister %d\n", index);
+
+ if (!hwif->configured)
goto abort;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
@@ -729,10 +835,18 @@
goto abort;
drive->dead = 1;
}
+ /*
+ * Protect against new users. From this point the hwif
+ * is not present so cannot be opened by a new I/O source.
+ * This also invalidates key driven access from procfs
+ */
+
+ was_present = hwif->present;
hwif->present = 0;
spin_unlock_irq(&ide_lock);
-
+ up(&ide_setting_sem);
+
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
if (!drive->present)
@@ -743,27 +857,36 @@
#ifdef CONFIG_PROC_FS
destroy_proc_ide_drives(hwif);
#endif
-
+ spin_lock_irq(&ide_lock);
+
hwgroup = hwif->hwgroup;
- /*
- * free the irq if we were the only hwif using it
- */
- g = hwgroup->hwif;
- do {
- if (g->irq == hwif->irq)
- ++irq_count;
- g = g->next;
- } while (g != hwgroup->hwif);
- if (irq_count == 1)
+ if(hwgroup)
+ {
+ /*
+ * free the irq if we were the only hwif using it
+ */
+ g = hwgroup->hwif;
+ do {
+ if (g->irq == hwif->irq)
+ ++irq_count;
+ g = g->next;
+ } while (g != hwgroup->hwif);
+ }
+ spin_unlock_irq(&ide_lock);
+
+ if (irq_count == 1 && hwgroup)
free_irq(hwif->irq, hwgroup);
- spin_lock_irq(&ide_lock);
/*
* Note that we only release the standard ports,
* and do not even try to handle any extra ports
* allocated for weird IDE interface chipsets.
+ *
+ * FIXME: should defer this I think
*/
- ide_hwif_release_regions(hwif);
+
+ if(was_present)
+ ide_hwif_release_regions(hwif);
/*
* Remove us from the hwgroup, and free
@@ -777,6 +900,14 @@
}
if (!drive->present)
continue;
+
+ /*
+ * The hwgroup chain is IRQ touched. We must protect
+ * walking this from an IDE event for another device
+ * in the chain
+ */
+
+ spin_lock_irq(&ide_lock);
if (drive == drive->next) {
/* special case: last drive from hwgroup. */
BUG_ON(hwgroup->drive != drive);
@@ -793,51 +924,73 @@
hwgroup->hwif = HWIF(hwgroup->drive);
}
}
+ spin_unlock_irq(&ide_lock);
+
+ /*
+ * The rest of the cleanup is private
+ */
+
BUG_ON(hwgroup->drive == drive);
if (drive->id != NULL) {
kfree(drive->id);
drive->id = NULL;
}
drive->present = 0;
- /* Messed up locking ... */
- spin_unlock_irq(&ide_lock);
blk_cleanup_queue(drive->queue);
device_unregister(&drive->gendev);
down(&drive->gendev_rel_sem);
- spin_lock_irq(&ide_lock);
drive->queue = NULL;
}
- if (hwif->next == hwif) {
- BUG_ON(hwgroup->hwif != hwif);
- kfree(hwgroup);
- } else {
- /* There is another interface in hwgroup.
- * Unlink us, and set hwgroup->drive and ->hwif to
- * something sane.
- */
- g = hwgroup->hwif;
- while (g->next != hwif)
- g = g->next;
- g->next = hwif->next;
- if (hwgroup->hwif == hwif) {
- /* Chose a random hwif for hwgroup->hwif.
- * It's guaranteed that there are no drives
- * left in the hwgroup.
+
+ /*
+ * Lock against hwgroup walkers including interrupts off other
+ * IDE devices wile we unhook ourselves.
+ */
+
+ spin_lock_irq(&ide_lock);
+
+ if (hwgroup)
+ {
+ if (hwif->next == hwif) {
+ BUG_ON(hwgroup->hwif != hwif);
+ kfree(hwgroup);
+ } else {
+ /* There is another interface in hwgroup.
+ * Unlink us, and set hwgroup->drive and ->hwif to
+ * something sane.
*/
- BUG_ON(hwgroup->drive != NULL);
- hwgroup->hwif = g;
+ g = hwgroup->hwif;
+ while (g->next != hwif)
+ g = g->next;
+ g->next = hwif->next;
+ if (hwgroup->hwif == hwif) {
+ /* Chose a random hwif for hwgroup->hwif.
+ * It's guaranteed that there are no drives
+ * left in the hwgroup.
+ */
+ BUG_ON(hwgroup->drive != NULL);
+ hwgroup->hwif = g;
+ }
+ BUG_ON(hwgroup->hwif == hwif);
}
- BUG_ON(hwgroup->hwif == hwif);
}
-
- /* More messed up locking ... */
spin_unlock_irq(&ide_lock);
- device_unregister(&hwif->gendev);
- down(&hwif->gendev_rel_sem);
+
+ /*
+ * PCI interfaces with no devices don't exist in the device
+ * tree so don't unregister them.
+ */
+
+ if(was_present)
+ {
+ device_unregister(&hwif->gendev);
+ down(&hwif->gendev_rel_sem);
+ }
/*
* Remove us from the kernel's knowledge
*/
+
blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
for (i = 0; i < MAX_DRIVES; i++) {
struct gendisk *disk = hwif->drives[i].disk;
@@ -845,8 +998,16 @@
put_disk(disk);
}
unregister_blkdev(hwif->major, hwif->name);
+
spin_lock_irq(&ide_lock);
+ /*
+ * Let the driver free up private objects
+ */
+
+ if(hwif->remove)
+ hwif->remove(hwif);
+
if (hwif->dma_base) {
(void) ide_release_dma(hwif);
@@ -858,24 +1019,70 @@
hwif->dma_vendor3 = 0;
hwif->dma_prdtable = 0;
}
+
+ hwif->chipset = ide_unknown;
/* copy original settings */
- *tmp_hwif = *hwif;
+ tmp_hwif = *hwif;
/* restore hwif data to pristine status */
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
+
+ hwif->key++;
+ hwif->configured = 0;
- ide_hwif_restore(hwif, tmp_hwif);
+ ide_hwif_restore(hwif, &tmp_hwif);
+
+ spin_unlock_irq(&ide_lock);
+ return 0;
abort:
+ if(hwif->configured)
+ {
+ printk("Unregister %d fail %d %d\n", index, drive->usage, DRIVER(drive)->busy);
+ ret = -EBUSY;
+ }
+ else
+ {
+ printk("No such hwif!\n");
+ ret = -ENOENT;
+ }
spin_unlock_irq(&ide_lock);
- up(&ide_cfg_sem);
+ up(&ide_setting_sem);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(__ide_unregister_hwif);
- kfree(tmp_hwif);
+
+/**
+ * ide_unregister_hwif - free an ide interface
+ * @hwif: interface to unregister
+ *
+ * Perform the final unregister of an IDE interface. At the moment
+ * we don't refcount interfaces so this will also get split up.
+ * Unregister restores the hwif structures to the default state.
+ *
+ * No locks should be held on entry. When an unregister must
+ * be done atomically with a register see __ide_unregister_hwif
+ * and hold the ide_cfg_sem yourself.
+ */
+
+int ide_unregister_hwif(ide_hwif_t *hwif)
+{
+ int ret;
+
+ /* This protects two things. Firstly it serializes the
+ shutdown sequence, secondly it protects us from
+ races while we are killing off a device */
+ down(&ide_cfg_sem);
+ ret = __ide_unregister_hwif(hwif);
+ up(&ide_cfg_sem);
+ return ret;
}
-EXPORT_SYMBOL(ide_unregister);
+EXPORT_SYMBOL_GPL(ide_unregister_hwif);
/**
@@ -931,15 +1138,25 @@
*/
}
-/*
- * Register an IDE interface, specifying exactly the registers etc
- * Set init=1 iff calling before probes have taken place.
+/**
+ * ide_register_hw - register IDE interface
+ * @hw: hardware registers
+ * @hwifp: pointer to returned hwif
+ *
+ * Register an IDE interface, specifying exactly the registers etc
+ * Set init=1 iff calling before probes have taken place. The
+ * ide_cfg_sem protects this against races.
+ *
+ * Returns -1 on error.
*/
+
int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
{
int index, retry = 1;
ide_hwif_t *hwif;
+ down(&ide_cfg_sem);
+
do {
for (index = 0; index < MAX_HWIFS; ++index) {
hwif = &ide_hwifs[index];
@@ -950,28 +1167,37 @@
hwif = &ide_hwifs[index];
if (hwif->hold)
continue;
- if ((!hwif->present && !hwif->mate && !initializing) ||
+ if ((!hwif->configured && !hwif->mate && !initializing) ||
(!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
goto found;
}
+ /* FIXME- this check should die as should the retry loop */
for (index = 0; index < MAX_HWIFS; index++)
- ide_unregister(index);
+ {
+ hwif = &ide_hwifs[index];
+ __ide_unregister_hwif(hwif);
+ }
} while (retry--);
+
+ up(&ide_cfg_sem);
return -1;
found:
- if (hwif->present)
- ide_unregister(index);
+ /* FIXME: do we really need this case */
+ if (hwif->configured)
+ __ide_unregister_hwif(hwif);
else if (!hwif->hold) {
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
}
- if (hwif->present)
+ if (hwif->configured)
return -1;
+ hwif->configured = 1;
memcpy(&hwif->hw, hw, sizeof(*hw));
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
hwif->irq = hw->irq;
hwif->noprobe = 0;
hwif->chipset = hw->chipset;
+ up(&ide_cfg_sem);
if (!initializing) {
probe_hwif_init(hwif);
@@ -1008,21 +1234,21 @@
* @set: setting
*
* Removes the setting named from the device if it is present.
- * The function takes the settings_lock to protect against
- * parallel changes. This function must not be called from IRQ
- * context. Returns 0 on success or -1 on failure.
+ * This function must not be called from IRQ context. Returns 0
+ * on success or -1 on failure.
*
* BUGS: This code is seriously over-engineered. There is also
* magic about how the driver specific features are setup. If
* a driver is attached we assume the driver settings are auto
* remove.
+ *
+ * The caller must hold settings_lock
*/
int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
{
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
- down(&ide_setting_sem);
while ((*p) && strcmp((*p)->name, name) < 0)
p = &((*p)->next);
if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
@@ -1046,10 +1272,8 @@
if (drive->driver != &idedefault_driver)
setting->auto_remove = 1;
*p = setting;
- up(&ide_setting_sem);
return 0;
abort:
- up(&ide_setting_sem);
if (setting)
kfree(setting);
return -1;
@@ -1058,7 +1282,7 @@
EXPORT_SYMBOL(ide_add_setting);
/**
- * __ide_remove_setting - remove an ide setting option
+ * ide_remove_setting - remove an ide setting option
* @drive: drive to use
* @name: setting name
*
@@ -1066,7 +1290,7 @@
* The caller must hold the setting semaphore.
*/
-static void __ide_remove_setting (ide_drive_t *drive, char *name)
+static void ide_remove_setting (ide_drive_t *drive, char *name)
{
ide_settings_t **p, *setting;
@@ -1144,7 +1368,7 @@
setting = drive->settings;
while (setting) {
if (setting->auto_remove) {
- __ide_remove_setting(drive, setting->name);
+ ide_remove_setting(drive, setting->name);
goto repeat;
}
setting = setting->next;
@@ -1322,25 +1556,19 @@
return err;
}
-int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
-{
- if (drive->media == ide_disk) {
- drive->scsi = 0;
- return 0;
- }
-
- if (DRIVER(drive)->cleanup(drive)) {
- drive->scsi = 0;
- return 0;
- }
-
- drive->scsi = (u8) arg;
- ata_attach(drive);
- return 0;
-}
+/**
+ * ide_add_generic_settings - generic /proc settings
+ * @drive: drive being configured
+ *
+ * Add the generic parts of the system settings to the /proc files
+ * for this IDE device. The caller must not be holding the settings_sem
+ * .lock
+ */
+
void ide_add_generic_settings (ide_drive_t *drive)
{
+ down(&ide_setting_sem);
/*
* drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
*/
@@ -1353,10 +1581,17 @@
ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL);
ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate);
ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL);
- if (drive->media != ide_disk)
- ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi);
+
+ up(&ide_setting_sem);
}
+/**
+ * system_bus_clock - clock guess
+ *
+ * External version of the bus clock guess used by old old IDE drivers
+ * for things like VLB timings. Should not be used.
+ */
+
int system_bus_clock (void)
{
return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
@@ -1364,52 +1599,42 @@
EXPORT_SYMBOL(system_bus_clock);
-/*
- * Locking is badly broken here - since way back. That sucker is
- * root-only, but that's not an excuse... The real question is what
- * exclusion rules do we want here.
+/**
+ * ata_attach - attach an ATA/ATAPI device
+ * @drive: drive to attach
+ *
+ * Takes a drive that is as yet not assigned to any midlayer IDE
+ * module and figures out which driver would like to own it. If
+ * nobody claims the driver then it is automatically attached
+ * to the default driver used for unclaimed objects.
+ *
+ * A return of zero indicates attachment to a driver, of one
+ * attachment to the default driver
+ *
+ * Takes the driver list lock and the ide_settings semaphore.
*/
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
- if (!drive->present || drive->usage || drive->dead)
- goto abort;
- if (DRIVER(drive)->cleanup(drive))
- goto abort;
- strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
- if (ata_attach(drive)) {
- spin_lock(&drives_lock);
- list_del_init(&drive->list);
- spin_unlock(&drives_lock);
- drive->driver_req[0] = 0;
- ata_attach(drive);
- } else {
- drive->driver_req[0] = 0;
- }
- if (DRIVER(drive)!= &idedefault_driver && !strcmp(DRIVER(drive)->name, driver))
- return 0;
-abort:
- return 1;
-}
-
+
int ata_attach(ide_drive_t *drive)
{
struct list_head *p;
- spin_lock(&drivers_lock);
+ down(&drivers_sem);
+ down(&ide_setting_sem);
list_for_each(p, &drivers) {
ide_driver_t *driver = list_entry(p, ide_driver_t, drivers);
if (!try_module_get(driver->owner))
continue;
- spin_unlock(&drivers_lock);
if (driver->attach(drive) == 0) {
module_put(driver->owner);
drive->gendev.driver = &driver->gen_driver;
+ up(&ide_setting_sem);
+ up(&drivers_sem);
return 0;
}
- spin_lock(&drivers_lock);
module_put(driver->owner);
}
drive->gendev.driver = &idedefault_driver.gen_driver;
- spin_unlock(&drivers_lock);
+ up(&ide_setting_sem);
+ up(&drivers_sem);
if(idedefault_driver.attach(drive) != 0)
panic("ide: default attach failed");
return 1;
@@ -1549,9 +1774,11 @@
}
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_RAWIO)) return -EACCES;
- /* (arg > MAX_HWIFS) checked in function */
- ide_unregister(arg);
- return 0;
+ if(arg > MAX_HWIFS || arg < 0)
+ return -EINVAL;
+ if(ide_hwifs[arg].pci_dev)
+ return -EINVAL;
+ return ide_unregister_hwif(&ide_hwifs[arg]);
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
@@ -2199,9 +2426,23 @@
EXPORT_SYMBOL(ide_register_subdriver);
+/**
+ * ide_unregister_subdriver - disconnect drive from driver
+ * @drive: drive to unplug
+ *
+ * Disconnect a drive from the driver it was attached to and then
+ * clean up the various proc files and other objects attached to it.
+ * Takes ide_sem, ide_lock, and drive_lock. Caller must hold none of
+ * the locks.
+ *
+ * No locking versus subdriver unload because we are moving to the
+ * default driver anyway. Wants double checking.
+ */
+
int ide_unregister_subdriver (ide_drive_t *drive)
{
unsigned long flags;
+ ide_proc_entry_t *dir;
down(&ide_setting_sem);
spin_lock_irqsave(&ide_lock, flags);
@@ -2210,13 +2451,14 @@
up(&ide_setting_sem);
return 1;
}
+ dir = DRIVER(drive)->proc;
+ drive->driver = &idedefault_driver;
+ spin_unlock_irqrestore(&ide_lock, flags);
#ifdef CONFIG_PROC_FS
- ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
+ ide_remove_proc_entries(drive->proc, dir);
ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
#endif
auto_remove_settings(drive);
- drive->driver = &idedefault_driver;
- spin_unlock_irqrestore(&ide_lock, flags);
up(&ide_setting_sem);
spin_lock(&drives_lock);
list_del_init(&drive->list);
@@ -2234,6 +2476,18 @@
return 0;
}
+/**
+ * ide_register_driver - new driver loaded
+ * @driver: the IDE driver module
+ *
+ * Register a new driver module and then scan the devices
+ * on the IDE bus in case any should be attached to the
+ * driver we have just attached. If so attach them
+ *
+ * Takes the drivers and drives lock. Should take the
+ * ide_sem but doesn't - FIXME
+ */
+
int ide_register_driver(ide_driver_t *driver)
{
struct list_head list;
@@ -2242,9 +2496,11 @@
setup_driver_defaults(driver);
+ down(&drivers_sem);
spin_lock(&drivers_lock);
list_add(&driver->drivers, &drivers);
spin_unlock(&drivers_lock);
+ up(&drivers_sem);
INIT_LIST_HEAD(&list);
spin_lock(&drives_lock);
@@ -2265,13 +2521,25 @@
EXPORT_SYMBOL(ide_register_driver);
+/**
+ * ide_unregister_driver - IDE module unload
+ * @driver: IDE driver module
+ *
+ * Unload a driver module and reattach any devices to whatever
+ * driver claims them next (typically the default driver). Takes
+ * the drivers lock, and called functions will take the
+ * IDE setting semaphore.
+ */
+
void ide_unregister_driver(ide_driver_t *driver)
{
ide_drive_t *drive;
+ down(&drivers_sem);
spin_lock(&drivers_lock);
list_del(&driver->drivers);
spin_unlock(&drivers_lock);
+ up(&drivers_sem);
driver_unregister(&driver->gen_driver);
@@ -2385,7 +2653,8 @@
int index;
for (index = 0; index < MAX_HWIFS; ++index) {
- ide_unregister(index);
+ if(ide_unregister_hwif(&ide_hwifs[index]))
+ printk(KERN_ERR "ide: unload yet busy!\n");
if (ide_hwifs[index].dma_base)
(void) ide_release_dma(&ide_hwifs[index]);
}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.8-rc3/include/linux/ide.h linux-2.6.8-rc3/include/linux/ide.h
--- linux.vanilla-2.6.8-rc3/include/linux/ide.h 2004-08-09 15:50:59.000000000 +0100
+++ linux-2.6.8-rc3/include/linux/ide.h 2004-08-12 16:45:17.000000000 +0100
@@ -1503,9 +1509,11 @@
extern void ide_pci_unregister_driver(struct pci_driver *driver);
extern void ide_pci_setup_ports(struct pci_dev *dev, struct ide_pci_device_s *d, int autodma, int pciirq, ata_index_t *index);
extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d);
+extern void ide_pci_remove_hwifs(struct pci_dev *dev);
extern void default_hwif_iops(ide_hwif_t *);
extern void default_hwif_mmiops(ide_hwif_t *);
+extern void removed_hwif_iops(ide_hwif_t *);
extern void default_hwif_transport(ide_hwif_t *);
int ide_register_driver(ide_driver_t *driver);
@@ -1603,8 +1611,9 @@
#endif
extern int ide_hwif_request_regions(ide_hwif_t *hwif);
-extern void ide_hwif_release_regions(ide_hwif_t* hwif);
-extern void ide_unregister (unsigned int index);
+extern void ide_hwif_release_regions(ide_hwif_t *hwif);
+extern int ide_unregister_hwif(ide_hwif_t *hwif);
+extern int __ide_unregister_hwif(ide_hwif_t *hwif);
extern int probe_hwif_init(ide_hwif_t *);
Signed-off-by: Alan Cox <alan@redhat.com>
next reply other threads:[~2004-08-15 15:14 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-08-15 15:13 Alan Cox [this message]
2004-08-16 17:23 ` PATCH: straighten out the IDE layer locking and add hotplug Bartlomiej Zolnierkiewicz
2004-08-16 17:36 ` Alan Cox
2004-08-16 22:29 ` Bartlomiej Zolnierkiewicz
2004-08-16 21:43 ` Bartlomiej Zolnierkiewicz
2004-08-16 21:48 ` Alan Cox
2004-08-17 13:12 ` Bartlomiej Zolnierkiewicz
2004-08-17 14:05 ` Alan Cox
2004-08-17 14:30 ` Bartlomiej Zolnierkiewicz
2004-08-17 14:46 ` Alan Cox
2004-08-17 15:05 ` Bartlomiej Zolnierkiewicz
2004-08-17 15:33 ` Alan Cox
2004-08-17 14:40 ` Bartlomiej Zolnierkiewicz
2004-08-17 14:12 ` Bartlomiej Zolnierkiewicz
2004-08-17 14:18 ` Alan Cox
2004-08-17 14:35 ` Bartlomiej Zolnierkiewicz
2004-08-17 16:11 ` Alan Cox
2004-08-17 20:40 ` Bartlomiej Zolnierkiewicz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20040815151346.GA13761@devserv.devel.redhat.com \
--to=alan@redhat.com \
--cc=linux-ide@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.