3.16.52-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Stange nstange@suse.de
commit 9561475db680f7144d2223a409dd3d7e322aca03 upstream.
The driver_override implementation is susceptible to a race condition when different threads are reading vs. storing a different driver override. Add locking to avoid the race condition.
This is in close analogy to commit 6265539776a0 ("driver core: platform: fix race condition with driver_override") from Adrian Salido.
Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") Signed-off-by: Nicolai Stange nstange@suse.de Signed-off-by: Bjorn Helgaas bhelgaas@google.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/pci/pci-sysfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
--- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -514,7 +514,7 @@ static ssize_t driver_override_store(str const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); - char *driver_override, *old = pdev->driver_override, *cp; + char *driver_override, *old, *cp;
/* We need to keep extra room for a newline */ if (count >= (PAGE_SIZE - 1)) @@ -528,12 +528,15 @@ static ssize_t driver_override_store(str if (cp) *cp = '\0';
+ device_lock(dev); + old = pdev->driver_override; if (strlen(driver_override)) { pdev->driver_override = driver_override; } else { kfree(driver_override); pdev->driver_override = NULL; } + device_unlock(dev);
kfree(old);
@@ -544,8 +547,12 @@ static ssize_t driver_override_show(stru struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); + ssize_t len;
- return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); + device_lock(dev); + len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); + device_unlock(dev); + return len; } static DEVICE_ATTR_RW(driver_override);