Re: PCI: Race condition in pci_create_sysfs_dev_files

From: Pali Rohár
Date: Wed Apr 07 2021 - 10:42:44 EST


On Thursday 16 July 2020 13:04:23 Pali Rohár wrote:
> Hello Bjorn!
>
> I see following error message in dmesg which looks like a race condition:
>
> sysfs: cannot create duplicate filename '/devices/platform/soc/d0070000.pcie/pci0000:00/0000:00:00.0/config'
>
> I looked at it deeper and found out that in PCI subsystem code is race
> condition between pci_bus_add_device() and pci_sysfs_init() calls. Both
> of these functions calls pci_create_sysfs_dev_files() and calling this
> function more times for same pci device throws above error message.
>
> There can be two different race conditions:
>
> 1. pci_bus_add_device() called pcibios_bus_add_device() or
> pci_fixup_device() but have not called pci_create_sysfs_dev_files() yet.
> Meanwhile pci_sysfs_init() is running and pci_create_sysfs_dev_files()
> was called for newly registered device. In this case function
> pci_create_sysfs_dev_files() is called two times, ones from
> pci_bus_add_device() and once from pci_sysfs_init().
>
> 2. pci_sysfs_init() is called. It first sets sysfs_initialized to 1
> which unblock calling pci_create_sysfs_dev_files(). Then another bus
> registers new PCI device and calls pci_bus_add_device() which calls
> pci_create_sysfs_dev_files() and registers sysfs files. Function
> pci_sysfs_init() continues execution and calls function
> pci_create_sysfs_dev_files() also for this newly registered device. So
> pci_create_sysfs_dev_files() is again called two times.
>
>
> I workaround both race conditions I created following hack patch. After
> applying it I'm not getting that 'sysfs: cannot create duplicate filename'
> error message anymore.

Scratch this hack patch, it contains another new race condition.

The only way how to get rid of this race condition is either to protect
whole "sysfs_initialized" variable by mutex or by completely removing
"sysfs_initialized" variable and therefore also removing function
pci_create_sysfs_dev_files(). I'm for second variant.