• Daniel Ritz's avatar
    [PATCH] Driver Core: fis bus rescan devices race · 4c898c7f
    Daniel Ritz authored
    bus_rescan_devices_helper() does not hold the dev->sem when it checks for
    !dev->driver().  device_attach() holds the sem, but calls again
    device_bind_driver() even when dev->driver is set.
    
    What happens is that a first device_attach() call (module insertion time)
    is on the way binding the device to a driver.  Another thread calls
    bus_rescan_devices().  Now when bus_rescan_devices_helper() checks for
    dev->driver it is still NULL 'cos the the prior device_attach() is not yet
    finished.  But as soon as the first one releases the dev->sem the second
    device_attach() tries to rebind the already bound device again.
    device_bind_driver() does this blindly which leads to a corrupt
    driver->klist_devices list (the device links itself, the head points to the
    device).  Later a call to device_release_driver() sets dev->driver to NULL
    and breaks the link it has to itself on knode_driver.  Rmmoding the driver
    later calls driver_detach() which leads to an endless loop 'cos the list
    head in klist_devices still points to the device.  And since dev->driver is
    NULL it's stuck with the same device forever.  Boom.  And rmmod hangs.
    
    Very easy to reproduce with new-style pcmcia and a 16bit card.  Just loop
    modprobe <pcmcia-modules> ;cardctl eject; rmmod <card driver, pcmcia
    modules>.
    
    Easiest fix is to check if the device is already bound to a driver in
    device_bind_driver().  This avoids the double binding.
    Signed-off-by: default avatarDaniel Ritz <daniel.ritz@gmx.ch>
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    4c898c7f
dd.c 6.16 KB