From: Hari Vyas <hari.vyas@broadcom.com>
To: Ray Jui <ray.jui@broadcom.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Subject: Re: [PATCH v1] PCI: Data corruption happening due to race condition
Date: Wed, 27 Jun 2018 22:02:10 +0530 [thread overview]
Message-ID: <CAM5rFu_28fwC6tnC9HG27KtHb0BNiBtdPWeTUxFAjwCv-Zs+Aw@mail.gmail.com> (raw)
In-Reply-To: <4a27d5b4-6578-8f91-fc6f-6409733f2e15@broadcom.com>
On Wed, Jun 27, 2018 at 9:57 PM, Ray Jui <ray.jui@broadcom.com> wrote:
> Are you re-sending v1 version of this patch or this is actually v2?
>
This is actually v2. Forgot to give version in first patch.
There was spin lock initialization issue with v1 which was not caught
in our environment.
In any case, I am trying out suggested priv_flag approach and testing it.
Hopefully that should be final version.
> Thanks,
>
> Ray
>
>
> On 6/27/2018 2:38 AM, Hari Vyas wrote:
>>
>> When a pci device is detected, a variable is_added is set to
>> 1 in pci device structure and proc, sys entries are created.
>>
>> When a pci device is removed, first is_added is checked for one
>> and then device is detached with clearing of proc and sys
>> entries and at end, is_added is set to 0.
>>
>> is_added and is_busmaster are bit fields in pci_dev structure
>> sharing same memory location.
>>
>> A strange issue was observed with multiple times removal and
>> rescan of a pcie nvme device using sysfs commands where is_added
>> flag was observed as zero instead of one while removing device
>> and proc,sys entries are not cleared. This causes issue in
>> later device addition with warning message "proc_dir_entry"
>> already registered.
>>
>> Debugging revealed a race condition between pcie core driver
>> enabling is_added bit(pci_bus_add_device()) and nvme driver
>> reset work-queue enabling is_busmaster bit (by pci_set_master()).
>> As both fields are not handled in atomic manner and that clears
>> is_added bit.
>>
>> Fix protects is_added and is_busmaster bits updation by a spin
>> locking mechanism.
>>
>> Signed-off-by: Hari Vyas <hari.vyas@broadcom.com>
>> Reviewed-by: Ray Jui <ray.jui@broadcom.com>
>> ---
>> drivers/pci/bus.c | 3 +++
>> drivers/pci/pci-driver.c | 2 ++
>> drivers/pci/pci.c | 7 +++++++
>> drivers/pci/probe.c | 1 +
>> drivers/pci/remove.c | 5 +++++
>> include/linux/pci.h | 1 +
>> 6 files changed, 19 insertions(+)
>>
>> diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
>> index 35b7fc8..61d389d 100644
>> --- a/drivers/pci/bus.c
>> +++ b/drivers/pci/bus.c
>> @@ -310,6 +310,7 @@ void __weak pcibios_bus_add_device(struct pci_dev
>> *pdev) { }
>> void pci_bus_add_device(struct pci_dev *dev)
>> {
>> int retval;
>> + unsigned long flags;
>> /*
>> * Can not put in pci_device_add yet because resources
>> @@ -330,7 +331,9 @@ void pci_bus_add_device(struct pci_dev *dev)
>> return;
>> }
>> + spin_lock_irqsave(&dev->lock, flags);
>> dev->is_added = 1;
>> + spin_unlock_irqrestore(&dev->lock, flags);
>> }
>> EXPORT_SYMBOL_GPL(pci_bus_add_device);
>> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
>> index c125d53..547bcd7 100644
>> --- a/drivers/pci/pci-driver.c
>> +++ b/drivers/pci/pci-driver.c
>> @@ -123,6 +123,8 @@ static ssize_t new_id_store(struct device_driver
>> *driver, const char *buf,
>> pdev->subsystem_device = subdevice;
>> pdev->class = class;
>> + spin_lock_init(&pdev->lock);
>> +
>> if (pci_match_id(pdrv->id_table, pdev))
>> retval = -EEXIST;
>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>> index 97acba7..bcb1f96 100644
>> --- a/drivers/pci/pci.c
>> +++ b/drivers/pci/pci.c
>> @@ -1649,6 +1649,7 @@ void pci_disable_enabled_device(struct pci_dev *dev)
>> void pci_disable_device(struct pci_dev *dev)
>> {
>> struct pci_devres *dr;
>> + unsigned long flags;
>> dr = find_pci_dr(dev);
>> if (dr)
>> @@ -1662,7 +1663,9 @@ void pci_disable_device(struct pci_dev *dev)
>> do_pci_disable_device(dev);
>> + spin_lock_irqsave(&dev->lock, flags);
>> dev->is_busmaster = 0;
>> + spin_unlock_irqrestore(&dev->lock, flags);
>> }
>> EXPORT_SYMBOL(pci_disable_device);
>> @@ -3664,6 +3667,7 @@ void __iomem *devm_pci_remap_cfg_resource(struct
>> device *dev,
>> static void __pci_set_master(struct pci_dev *dev, bool enable)
>> {
>> u16 old_cmd, cmd;
>> + unsigned long flags;
>> pci_read_config_word(dev, PCI_COMMAND, &old_cmd);
>> if (enable)
>> @@ -3675,7 +3679,10 @@ static void __pci_set_master(struct pci_dev *dev,
>> bool enable)
>> enable ? "enabling" : "disabling");
>> pci_write_config_word(dev, PCI_COMMAND, cmd);
>> }
>> +
>> + spin_lock_irqsave(&dev->lock, flags);
>> dev->is_busmaster = enable;
>> + spin_unlock_irqrestore(&dev->lock, flags);
>> }
>> /**
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index ac876e3..9203b88 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -2102,6 +2102,7 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
>> INIT_LIST_HEAD(&dev->bus_list);
>> dev->dev.type = &pci_dev_type;
>> dev->bus = pci_bus_get(bus);
>> + spin_lock_init(&dev->lock);
>> return dev;
>> }
>> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
>> index 6f072ea..ff57bd6 100644
>> --- a/drivers/pci/remove.c
>> +++ b/drivers/pci/remove.c
>> @@ -17,13 +17,18 @@ static void pci_free_resources(struct pci_dev *dev)
>> static void pci_stop_dev(struct pci_dev *dev)
>> {
>> + unsigned long flags;
>> +
>> pci_pme_active(dev, false);
>> if (dev->is_added) {
>> device_release_driver(&dev->dev);
>> pci_proc_detach_device(dev);
>> pci_remove_sysfs_dev_files(dev);
>> +
>> + spin_lock_irqsave(&dev->lock, flags);
>> dev->is_added = 0;
>> + spin_unlock_irqrestore(&dev->lock, flags);
>> }
>> if (dev->bus->self)
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index 340029b..6940825 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -365,6 +365,7 @@ struct pci_dev {
>> bool match_driver; /* Skip attaching driver
>> */
>> + spinlock_t lock; /* Protect is_added and
>> is_busmaster */
>> unsigned int transparent:1; /* Subtractive decode
>> bridge */
>> unsigned int multifunction:1; /* Multi-function device
>> */
>>
next prev parent reply other threads:[~2018-06-27 16:32 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-25 10:10 [PATCH] PCI: Data corruption happening due to race condition Hari Vyas
2018-06-25 10:37 ` Lukas Wunner
2018-06-25 10:57 ` Hari Vyas
2018-06-25 11:15 ` Lukas Wunner
2018-06-26 10:17 ` Hari Vyas
2018-06-26 11:53 ` Lukas Wunner
2018-06-27 9:38 ` [PATCH v1] " Hari Vyas
2018-06-27 16:27 ` Ray Jui
2018-06-27 16:32 ` Hari Vyas [this message]
2018-06-27 16:36 ` Ray Jui
2018-06-28 11:23 ` Hari Vyas
[not found] ` <CAM5rFu-Sb5Vhvy19GKesV00=tf0+7Q8hByU11=4F9MVhoO7nWA@mail.gmail.com>
[not found] ` <20180627124920.GA27447@wunner.de>
2018-06-27 13:00 ` [PATCH] " Hari Vyas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAM5rFu_28fwC6tnC9HG27KtHb0BNiBtdPWeTUxFAjwCv-Zs+Aw@mail.gmail.com \
--to=hari.vyas@broadcom.com \
--cc=bhelgaas@google.com \
--cc=linux-pci@vger.kernel.org \
--cc=ray.jui@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).