• Hari Vyas's avatar
    PCI: Fix is_added/is_busmaster race condition · 44bda4b7
    Hari Vyas authored
    When a PCI device is detected, pdev->is_added is set to 1 and proc and
    sysfs entries are created.
    
    When the device is removed, pdev->is_added is checked for one and then
    device is detached with clearing of proc and sys entries and at end,
    pdev->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 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 the PCI core setting the
    is_added bit in pci_bus_add_device() and the NVMe driver reset work-queue
    setting the is_busmaster bit in pci_set_master().  As these fields are not
    handled atomically, that clears the is_added bit.
    
    Move the is_added bit to a separate private flag variable and use atomic
    functions to set and retrieve the device addition state.  This avoids the
    race because is_added no longer shares a memory location with is_busmaster.
    
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=200283Signed-off-by: default avatarHari Vyas <hari.vyas@broadcom.com>
    Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
    Reviewed-by: default avatarLukas Wunner <lukas@wunner.de>
    Acked-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
    44bda4b7
pci-common.c 45.5 KB