]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
generic: 6.12: add pending patch to address PCI sysfs creation entry race 18989/head
authorChristian Marangi <ansuelsmth@gmail.com>
Mon, 13 Oct 2025 23:12:34 +0000 (01:12 +0200)
committerChristian Marangi <ansuelsmth@gmail.com>
Tue, 14 Oct 2025 08:27:30 +0000 (10:27 +0200)
Add pending patch to address PCI sysfs creation entry race observed on
ipq806x. This is to handle a kernel warning on creating the same sysfs
entry multiple times.

All affected patch automatically refreshed.

Link: https://github.com/openwrt/openwrt/pull/18989
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
target/linux/generic/pending-6.12/812-PCI-sysfs-enforce-single-creation-of-sysfs-entry-for.patch [new file with mode: 0644]
target/linux/lantiq/patches-6.12/001-MIPS-lantiq-add-pcie-driver.patch

diff --git a/target/linux/generic/pending-6.12/812-PCI-sysfs-enforce-single-creation-of-sysfs-entry-for.patch b/target/linux/generic/pending-6.12/812-PCI-sysfs-enforce-single-creation-of-sysfs-entry-for.patch
new file mode 100644 (file)
index 0000000..edb15e9
--- /dev/null
@@ -0,0 +1,142 @@
+From d33941523a8379e30070374b133b28a2077dcef8 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Mon, 13 Oct 2025 20:45:25 +0200
+Subject: [PATCH] PCI/sysfs: enforce single creation of sysfs entry for pdev
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In some specific scenario it's possible that the
+pci_create_resource_files() gets called multiple times and the created
+entry actually gets wrongly deleted with extreme case of having a NULL
+pointer dereference when the PCI is removed.
+
+This mainly happen due to bad timing where the PCI bus is adding PCI
+devices and at the same time the sysfs code is adding the entry causing
+double execution of the pci_create_resource_files function and kernel
+WARNING.
+
+To be more precise there is a race between the late_initcall of
+pci-sysfs with pci_sysfs_init and PCI bus.c pci_bus_add_device that also
+call pci_create_sysfs_dev_files.
+
+With correct amount of ""luck"" (or better say bad luck)
+pci_create_sysfs_dev_files in bus.c might be called with pci_sysfs_init
+is executing the loop.
+
+This has been reported multiple times and on multiple system, like imx6
+system, ipq806x systems...
+
+To address this, imlement multiple improvement to the implementation:
+1. Add a bool to pci_dev to flag when sysfs entry are created
+   (sysfs_init)
+2. Implement a simple completion to wait pci_sysfs_init execution.
+3. Permit additional call of pci_create_sysfs_dev_files only after
+   pci_sysfs_init has finished.
+
+With such logic in place, we address al kind of timing problem with
+minimal change to any driver.
+
+A notice worth to mention is that the remove function are not affected
+by this as the pci_remove_resource_files have enough check in place to
+always work and it's always called by pci_stop_dev.
+
+Cc: stable@vger.kernel.org
+Reported-by: Krzysztof HaƂasa <khalasa@piap.pl>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=215515
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+---
+ drivers/pci/pci-sysfs.c | 34 +++++++++++++++++++++++++++++-----
+ include/linux/pci.h     |  1 +
+ 2 files changed, 30 insertions(+), 5 deletions(-)
+
+--- a/drivers/pci/pci-sysfs.c
++++ b/drivers/pci/pci-sysfs.c
+@@ -13,6 +13,7 @@
+  */
+ #include <linux/bitfield.h>
++#include <linux/completion.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/pci.h>
+@@ -36,6 +37,7 @@
+ #endif
+ static int sysfs_initialized; /* = 0 */
++static DECLARE_COMPLETION(sysfs_init_completion);
+ /* show configuration fields */
+ #define pci_config_attr(field, format_string)                         \
+@@ -1533,12 +1535,32 @@ static const struct attribute_group pci_
+       .is_visible = resource_resize_is_visible,
+ };
++static int __pci_create_sysfs_dev_files(struct pci_dev *pdev)
++{
++      int ret;
++
++      ret = pci_create_resource_files(pdev);
++      if (ret)
++              return ret;
++
++      /* on success set sysfs correctly created */
++      pdev->sysfs_init = true;
++      return 0;
++}
++
+ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
+ {
+       if (!sysfs_initialized)
+               return -EACCES;
+-      return pci_create_resource_files(pdev);
++      /* sysfs entry already created */
++      if (pdev->sysfs_init)
++              return 0;
++
++      /* wait for pci_sysfs_init */
++      wait_for_completion(&sysfs_init_completion);
++
++      return __pci_create_sysfs_dev_files(pdev);
+ }
+ /**
+@@ -1559,21 +1581,23 @@ static int __init pci_sysfs_init(void)
+ {
+       struct pci_dev *pdev = NULL;
+       struct pci_bus *pbus = NULL;
+-      int retval;
++      int retval = 0;
+       sysfs_initialized = 1;
+       for_each_pci_dev(pdev) {
+-              retval = pci_create_sysfs_dev_files(pdev);
++              retval = __pci_create_sysfs_dev_files(pdev);
+               if (retval) {
+                       pci_dev_put(pdev);
+-                      return retval;
++                      goto exit;
+               }
+       }
+       while ((pbus = pci_find_next_bus(pbus)))
+               pci_create_legacy_files(pbus);
+-      return 0;
++exit:
++      complete_all(&sysfs_init_completion);
++      return retval;
+ }
+ late_initcall(pci_sysfs_init);
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -484,6 +484,7 @@ struct pci_dev {
+       unsigned int    rom_attr_enabled:1;     /* Display of ROM attribute enabled? */
+       pci_dev_flags_t dev_flags;
+       atomic_t        enable_cnt;     /* pci_enable_device has been called */
++      bool            sysfs_init;     /* sysfs entry has been created */
+       spinlock_t      pcie_cap_lock;          /* Protects RMW ops in capability accessors */
+       u32             saved_config_space[16]; /* Config space saved at suspend time */
index f325607dbf184d337d7c73746a198c29a159b914..a49eaf66ab0699e30edbc9b4859551188cdcec3c 100644 (file)
@@ -5518,7 +5518,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
          (transaction layer end-to-end CRC checking).
 --- a/include/linux/pci.h
 +++ b/include/linux/pci.h
-@@ -1643,6 +1643,8 @@ void pci_walk_bus_locked(struct pci_bus
+@@ -1644,6 +1644,8 @@ void pci_walk_bus_locked(struct pci_bus
                         void *userdata);
  int pci_cfg_space_size(struct pci_dev *dev);
  unsigned char pci_bus_max_busnr(struct pci_bus *bus);