There is a race between shutdown and creation of devices:  fw-core may
attempt to add a device with the same name of an already existing
device.  http://bugzilla.kernel.org/show_bug.cgi?id=9828

Impact of the bug:  Happens rarely, forces the user to unplug and replug
the new device to get it working.

The fix moves deregistration of the minor number and device_unregister()
into a common rw_sem protected section.

We also move the ref count increment from fw_device_op_open into an
rw_sem protected section with the lookup of the device, so that the
device pointer can't become invalid between lookup and usage.

Signed-off-by: Stefan Richter <[EMAIL PROTECTED]>
---
 drivers/firewire/fw-cdev.c   |    6 ++++--
 drivers/firewire/fw-device.c |   10 ++++++----
 2 files changed, 10 insertions(+), 6 deletions(-)

Index: linux/drivers/firewire/fw-device.c
===================================================================
--- linux.orig/drivers/firewire/fw-device.c
+++ linux/drivers/firewire/fw-device.c
@@ -614,10 +614,12 @@ struct fw_device *fw_device_from_devt(de
 {
        struct fw_device *device;
 
        down_read(&idr_rwsem);
        device = idr_find(&fw_device_idr, MINOR(devt));
+       if (device)
+               fw_device_get(device);
        up_read(&idr_rwsem);
 
        return device;
 }
 
@@ -625,17 +627,17 @@ static void fw_device_shutdown(struct wo
 {
        struct fw_device *device =
                container_of(work, struct fw_device, work.work);
        int minor = MINOR(device->device.devt);
 
-       down_write(&idr_rwsem);
-       idr_remove(&fw_device_idr, minor);
-       up_write(&idr_rwsem);
-
        fw_device_cdev_remove(device);
        device_for_each_child(&device->device, NULL, shutdown_unit);
+
+       down_write(&idr_rwsem);
        device_unregister(&device->device);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&idr_rwsem);
 }
 
 static struct device_type fw_device_type = {
        .release        = fw_device_release,
 };
Index: linux/drivers/firewire/fw-cdev.c
===================================================================
--- linux.orig/drivers/firewire/fw-cdev.c
+++ linux/drivers/firewire/fw-cdev.c
@@ -112,14 +112,16 @@ static int fw_device_op_open(struct inod
        device = fw_device_from_devt(inode->i_rdev);
        if (device == NULL)
                return -ENODEV;
 
        client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
+       if (client == NULL) {
+               fw_device_put(device);
                return -ENOMEM;
+       }
 
-       client->device = fw_device_get(device);
+       client->device = device;
        INIT_LIST_HEAD(&client->event_list);
        INIT_LIST_HEAD(&client->resource_list);
        spin_lock_init(&client->lock);
        init_waitqueue_head(&client->wait);
 

-- 
Stefan Richter
-=====-==--- ---= ==-==
http://arcgraph.de/sr/

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to