summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorNicolai Stange <nstange@suse.de>2017-09-11 03:45:40 -0400
committerBjorn Helgaas <bhelgaas@google.com>2017-09-25 19:34:54 -0400
commit9561475db680f7144d2223a409dd3d7e322aca03 (patch)
tree34aa91f19f3c51bd13402386634f00ac38031371 /drivers/pci
parentfe59493240169a2cc3f445ae5f2a2308fda06b63 (diff)
PCI: Fix race condition with driver_override
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> Cc: stable@vger.kernel.org # v3.16+
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-sysfs.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 1eecfa301f7f..8e075ea2743e 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -686,7 +686,7 @@ static ssize_t driver_override_store(struct device *dev,
686 const char *buf, size_t count) 686 const char *buf, size_t count)
687{ 687{
688 struct pci_dev *pdev = to_pci_dev(dev); 688 struct pci_dev *pdev = to_pci_dev(dev);
689 char *driver_override, *old = pdev->driver_override, *cp; 689 char *driver_override, *old, *cp;
690 690
691 /* We need to keep extra room for a newline */ 691 /* We need to keep extra room for a newline */
692 if (count >= (PAGE_SIZE - 1)) 692 if (count >= (PAGE_SIZE - 1))
@@ -700,12 +700,15 @@ static ssize_t driver_override_store(struct device *dev,
700 if (cp) 700 if (cp)
701 *cp = '\0'; 701 *cp = '\0';
702 702
703 device_lock(dev);
704 old = pdev->driver_override;
703 if (strlen(driver_override)) { 705 if (strlen(driver_override)) {
704 pdev->driver_override = driver_override; 706 pdev->driver_override = driver_override;
705 } else { 707 } else {
706 kfree(driver_override); 708 kfree(driver_override);
707 pdev->driver_override = NULL; 709 pdev->driver_override = NULL;
708 } 710 }
711 device_unlock(dev);
709 712
710 kfree(old); 713 kfree(old);
711 714
@@ -716,8 +719,12 @@ static ssize_t driver_override_show(struct device *dev,
716 struct device_attribute *attr, char *buf) 719 struct device_attribute *attr, char *buf)
717{ 720{
718 struct pci_dev *pdev = to_pci_dev(dev); 721 struct pci_dev *pdev = to_pci_dev(dev);
722 ssize_t len;
719 723
720 return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); 724 device_lock(dev);
725 len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
726 device_unlock(dev);
727 return len;
721} 728}
722static DEVICE_ATTR_RW(driver_override); 729static DEVICE_ATTR_RW(driver_override);
723 730