we noticed a change in module loading behavior and tracked it backwards to a small change in behavior due to 774a1221e862b343388347bac9b318767336b20b. this tries to avoid queuing if possible, but if we do queue then copy the relevant task flag on the target cpu. \p
From 9e77188d8a8e74b7b4e3f3e7c6bb0deb8fdf7eb4 Mon Sep 17 00:00:00 2001 From: peter chang <dpf@xxxxxxxxxx> Date: Mon, 27 Jan 2014 16:24:53 -0800 Subject: [PATCH] platforms: avoid queuing work if possible 774a1221e862b343388347bac9b318767336b20b tries to avoid an expensive sync by marking the current task iff it uses the async_schedule() machinery. however, if the part of the driver's probe is called through a worker thread the bookeeping fails to mark the correct task as having used the async machinery. this is a workaround for the common case that we're already running on the correct cpu. however, it seems sort of reasonable to not use the worker thread if we don't have to. Tested: - checked on vebmy2 (ibis + satasquatch) which is where the original issue was discovered. - checked on fdha347 (ikaria + loggerhead + satasquatch) to show that nothing changed. Change-Id: Ibe8996cf652735c74a9e06ba9fd03118078395bd Google-Bug-Id: 12632867 Signed-off-by: peter chang <dpf@xxxxxxxxxx> --- drivers/pci/pci-driver.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e6515e2..9f7e1e9 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -243,6 +243,7 @@ struct drv_dev_and_id { struct pci_driver *drv; struct pci_dev *dev; const struct pci_device_id *id; + unsigned int task_flags; }; static long local_pci_probe(void *_ddi) @@ -267,7 +268,8 @@ static long local_pci_probe(void *_ddi) if (rc) { pci_dev->driver = NULL; pm_runtime_put_sync(dev); - } + } else if (current) + ddi->task_flags = current->flags; return rc; } @@ -275,7 +277,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, const struct pci_device_id *id) { int error, node; - struct drv_dev_and_id ddi = { drv, dev, id }; + struct drv_dev_and_id ddi = { drv, dev, id, 0 }; /* Execute driver initialization on node where the device's bus is attached to. This way the driver likely allocates @@ -287,9 +289,16 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, get_online_cpus(); cpu = cpumask_any_and(cpumask_of_node(node), cpu_online_mask); - if (cpu < nr_cpu_ids) + /* try not to queue work if we're already on the target cpu */ + if (cpu < nr_cpu_ids && cpu != get_cpu()) { error = work_on_cpu(cpu, local_pci_probe, &ddi); - else + /* copy out some task flags for the module loading + * case. + */ + if (!error && current) + current->flags |= (ddi.task_flags & + PF_USED_ASYNC); + } else error = local_pci_probe(&ddi); put_online_cpus(); } else -- 1.8.5.3