Commit e981e795 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dt-for-linus' of git://git.secretlab.ca/git/linux

Pull driver core deferred probe fix from Grant Likely:
 "Drivercore race condition fix (exposed by devicetree)

  This branch fixes a bug where a device can get stuck in the deferred
  list even though all its dependencies are met.  The bug has existed
  for a long time, but new platform conversions to device tree have
  exposed it.  This patch is needed to get those platforms working.

  This was the pending bug fix I mentioned in my previous pull request.
  Normally this would go through Greg's tree seeing that it is a
  drivercore change, but devicetree exposes the problem.  I've discussed
  with Greg and he okayed me asking you to pull directly"

* tag 'dt-for-linus' of git://git.secretlab.ca/git/linux:
  drivercore: deferral race condition fix
parents 54366a7f 58b116bc
...@@ -52,6 +52,7 @@ static DEFINE_MUTEX(deferred_probe_mutex); ...@@ -52,6 +52,7 @@ static DEFINE_MUTEX(deferred_probe_mutex);
static LIST_HEAD(deferred_probe_pending_list); static LIST_HEAD(deferred_probe_pending_list);
static LIST_HEAD(deferred_probe_active_list); static LIST_HEAD(deferred_probe_active_list);
static struct workqueue_struct *deferred_wq; static struct workqueue_struct *deferred_wq;
static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
/** /**
* deferred_probe_work_func() - Retry probing devices in the active list. * deferred_probe_work_func() - Retry probing devices in the active list.
...@@ -135,6 +136,17 @@ static bool driver_deferred_probe_enable = false; ...@@ -135,6 +136,17 @@ static bool driver_deferred_probe_enable = false;
* This functions moves all devices from the pending list to the active * This functions moves all devices from the pending list to the active
* list and schedules the deferred probe workqueue to process them. It * list and schedules the deferred probe workqueue to process them. It
* should be called anytime a driver is successfully bound to a device. * should be called anytime a driver is successfully bound to a device.
*
* Note, there is a race condition in multi-threaded probe. In the case where
* more than one device is probing at the same time, it is possible for one
* probe to complete successfully while another is about to defer. If the second
* depends on the first, then it will get put on the pending list after the
* trigger event has already occured and will be stuck there.
*
* The atomic 'deferred_trigger_count' is used to determine if a successful
* trigger has occurred in the midst of probing a driver. If the trigger count
* changes in the midst of a probe, then deferred processing should be triggered
* again.
*/ */
static void driver_deferred_probe_trigger(void) static void driver_deferred_probe_trigger(void)
{ {
...@@ -147,6 +159,7 @@ static void driver_deferred_probe_trigger(void) ...@@ -147,6 +159,7 @@ static void driver_deferred_probe_trigger(void)
* into the active list so they can be retried by the workqueue * into the active list so they can be retried by the workqueue
*/ */
mutex_lock(&deferred_probe_mutex); mutex_lock(&deferred_probe_mutex);
atomic_inc(&deferred_trigger_count);
list_splice_tail_init(&deferred_probe_pending_list, list_splice_tail_init(&deferred_probe_pending_list,
&deferred_probe_active_list); &deferred_probe_active_list);
mutex_unlock(&deferred_probe_mutex); mutex_unlock(&deferred_probe_mutex);
...@@ -265,6 +278,7 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); ...@@ -265,6 +278,7 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
static int really_probe(struct device *dev, struct device_driver *drv) static int really_probe(struct device *dev, struct device_driver *drv)
{ {
int ret = 0; int ret = 0;
int local_trigger_count = atomic_read(&deferred_trigger_count);
atomic_inc(&probe_count); atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n", pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
...@@ -310,6 +324,9 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -310,6 +324,9 @@ static int really_probe(struct device *dev, struct device_driver *drv)
/* Driver requested deferred probing */ /* Driver requested deferred probing */
dev_info(dev, "Driver %s requests probe deferral\n", drv->name); dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev); driver_deferred_probe_add(dev);
/* Did a trigger occur while probing? Need to re-trigger if yes */
if (local_trigger_count != atomic_read(&deferred_trigger_count))
driver_deferred_probe_trigger();
} else if (ret != -ENODEV && ret != -ENXIO) { } else if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */ /* driver matched but the probe failed */
printk(KERN_WARNING printk(KERN_WARNING
......
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