]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: Initialize temporary device in new_id_store()
authorSamiullah Khawaja <skhawaja@google.com>
Tue, 5 May 2026 23:43:27 +0000 (23:43 +0000)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 8 May 2026 20:50:06 +0000 (15:50 -0500)
When setting new_id of a PCI device driver using sysfs a lockdep splat
occurs. This is because new_id_store() builds a temporary pci_dev for
pci_match_device(), which calls device_match_driver_override().  That
depends on the driver_override.lock added by cb3d1049f4ea ("driver core:
generalize driver_override in struct device").

The new driver_override.lock was not initialized in the temporary pci_dev,
resulting in this lockdep splat.

Initialize the temporary pci_dev to fix this.

Repro:

  Build with CONFIG_LOCKDEP=y, boot with QEMU, and add a new ID:

  # echo "8086 10f5" > /sys/bus/pci/drivers/e1000e/new_id

  INFO: trying to register non-static key.
  The code is fine but needs lockdep annotation, or maybe
  you didn't initialize this object before use?
  turning off the locking correctness validator.
  CPU: 2 UID: 0 PID: 177 Comm: liveupdate-iomm Not tainted 7.0.0+ #9 PREEMPT(full)
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
  Call Trace:
   <TASK>
   dump_stack_lvl+0x5d/0x80
   register_lock_class+0x77e/0x790
   lock_acquire+0xbf/0x2e0
   pci_match_device+0x24/0x180
   new_id_store+0x189/0x1d0
   kernfs_fop_write_iter+0x14f/0x210
   vfs_write+0x263/0x5e0
   ksys_write+0x79/0xf0
   do_syscall_64+0x117/0xf80

Fixes: 10a4206a2401 ("PCI: use generic driver_override infrastructure")
Fixes: 8895d3bcb8ba ("PCI: Fail new_id for vendor/device values already built into driver")
Signed-off-by: Samiullah Khawaja <skhawaja@google.com>
[bhelgaas: add commit log details and repro, trim backtrace]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260505234327.716630-1-skhawaja@google.com
drivers/pci/pci-driver.c

index d10ece0889f0f4f1d843c87040e116c89860af4c..e3f59001785a17038b3ff0e2d7fb84be79f4df72 100644 (file)
@@ -179,6 +179,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
        return NULL;
 }
 
+static void _pci_free_device(struct device *dev)
+{
+       kfree(to_pci_dev(dev));
+}
+
 /**
  * new_id_store - sysfs frontend to pci_add_dynid()
  * @driver: target device driver
@@ -214,11 +219,13 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
                pdev->subsystem_vendor = subvendor;
                pdev->subsystem_device = subdevice;
                pdev->class = class;
+               pdev->dev.release = _pci_free_device;
 
+               device_initialize(&pdev->dev);
                if (pci_match_device(pdrv, pdev))
                        retval = -EEXIST;
 
-               kfree(pdev);
+               put_device(&pdev->dev);
 
                if (retval)
                        return retval;