]> git.hungrycats.org Git - linux/commitdiff
[PATCH] ide: fix ide_unregister() vs. driver model
authorBartlomiej Zolnierkiewicz <b.zolnierkiewicz@elka.pw.edu.pl>
Tue, 2 Sep 2003 00:43:31 +0000 (17:43 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Tue, 2 Sep 2003 00:43:31 +0000 (17:43 -0700)
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.

drivers/ide/ide-probe.c
drivers/ide/ide.c
include/linux/ide.h

index f0c5cc5b5685be661b730606a84cc21dbd8bd030..cb18ac6fa2b75be0e12944920e61ea8adc1a19f5 100644 (file)
@@ -644,6 +644,13 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
        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)
 {
        /* register with global device tree */
@@ -656,6 +663,7 @@ static void hwif_register (ide_hwif_t *hwif)
                        /* Would like to do = &device_legacy */
                        hwif->gendev.parent = NULL;
        }
+       hwif->gendev.release = hwif_release_dev;
        device_register(&hwif->gendev);
 }
 
@@ -1196,6 +1204,13 @@ 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,
  * after probing for drives, to allocate partition tables and other data
@@ -1214,6 +1229,7 @@ static void init_gendisk (ide_hwif_t *hwif)
                drive->gendev.parent = &hwif->gendev;
                drive->gendev.bus = &ide_bus_type;
                drive->gendev.driver_data = drive;
+               drive->gendev.release = drive_release_dev;
                if (drive->present) {
                        device_register(&drive->gendev);
                        sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
index 387503fa87df6d0bf3a3ab52824370a4537c4320..8ff22ad3f648e155a1065349b377999f21792bce 100644 (file)
@@ -251,6 +251,8 @@ static void init_hwif_data (unsigned int index)
        hwif->mwdma_mask = 0x80;        /* disable all mwdma */
        hwif->swdma_mask = 0x80;        /* disable all swdma */
 
+       sema_init(&hwif->gendev_rel_sem, 0);
+
        default_hwif_iops(hwif);
        default_hwif_transport(hwif);
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -273,6 +275,7 @@ static void init_hwif_data (unsigned int index)
                drive->driver                   = &idedefault_driver;
                drive->vdma                     = 0;
                INIT_LIST_HEAD(&drive->list);
+               sema_init(&drive->gendev_rel_sem, 0);
        }
 }
 
@@ -745,6 +748,7 @@ void ide_unregister (unsigned int index)
                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;
        }
@@ -774,6 +778,7 @@ void ide_unregister (unsigned int index)
        /* More messed up locking ... */
        spin_unlock_irq(&ide_lock);
        device_unregister(&hwif->gendev);
+       down(&hwif->gendev_rel_sem);
 
        /*
         * Remove us from the kernel's knowledge
index 98a1a968ad93ca850cea9398671e2dfaf515fe41..4664fd44a98626c97d8cd2dbb90d9d9f9035e008 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/system.h>
 #include <asm/hdreg.h>
 #include <asm/io.h>
+#include <asm/semaphore.h>
 
 #define DEBUG_PM
 
@@ -774,6 +775,7 @@ typedef struct ide_drive_s {
        int             crc_count;      /* crc counter to reduce drive speed */
        struct list_head list;
        struct device   gendev;
+       struct semaphore gendev_rel_sem;        /* to deal with device release() */
        struct gendisk *disk;
 } ide_drive_t;
 
@@ -1040,6 +1042,7 @@ typedef struct hwif_s {
        unsigned        auto_poll  : 1; /* supports nop auto-poll */
 
        struct device   gendev;
+       struct semaphore gendev_rel_sem; /* To deal with device release() */
 
        void            *hwif_data;     /* extra hwif data */