From: Rafael J. Wysocki Date: Sun, 24 Nov 2013 00:17:52 +0000 (+0100) Subject: PCI: Move device_del() from pci_stop_dev() to pci_destroy_dev() X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=4bff6749905d3abe7436d3b2d20b626886a04475;p=linux-beck.git PCI: Move device_del() from pci_stop_dev() to pci_destroy_dev() After commit bcdde7e221a8 (sysfs: make __sysfs_remove_dir() recursive) I'm seeing traces analogous to the one below in Thunderbolt testing: WARNING: CPU: 3 PID: 76 at /scratch/rafael/work/linux-pm/fs/sysfs/group.c:214 sysfs_remove_group+0x59/0xe0() sysfs group ffffffff81c6c500 not found for kobject '0000:08' Modules linked in: ... CPU: 3 PID: 76 Comm: kworker/u16:7 Not tainted 3.13.0-rc1+ #76 Hardware name: Acer Aspire S5-391/Venus , BIOS V1.02 05/29/2012 Workqueue: kacpi_hotplug acpi_hotplug_work_fn 0000000000000009 ffff8801644b9ac8 ffffffff816b23bf 0000000000000007 ffff8801644b9b18 ffff8801644b9b08 ffffffff81046607 ffff88016925b800 0000000000000000 ffffffff81c6c500 ffff88016924f928 ffff88016924f800 Call Trace: [] dump_stack+0x4e/0x71 [] warn_slowpath_common+0x87/0xb0 [] warn_slowpath_fmt+0x41/0x50 [] ? sysfs_get_dirent_ns+0x6f/0x80 [] sysfs_remove_group+0x59/0xe0 [] dpm_sysfs_remove+0x3b/0x50 [] device_del+0x58/0x1c0 [] device_unregister+0x48/0x60 [] pci_remove_bus+0x6e/0x80 [] pci_remove_bus_device+0x38/0x110 [] pci_remove_bus_device+0x4d/0x110 [] pci_stop_and_remove_bus_device+0x19/0x20 [] disable_slot+0x20/0xe0 [] acpiphp_check_bridge+0xa8/0xd0 [] hotplug_event+0x17d/0x220 [] hotplug_event_work+0x30/0x70 [] acpi_hotplug_work_fn+0x18/0x24 [] process_one_work+0x261/0x450 [] worker_thread+0x21e/0x370 [] ? rescuer_thread+0x300/0x300 [] kthread+0xd2/0xe0 [] ? flush_kthread_worker+0x70/0x70 [] ret_from_fork+0x7c/0xb0 [] ? flush_kthread_worker+0x70/0x70 (Mika Westerberg sees them too in his tests). Some investigation documented in kernel bug #65281 led me to the conclusion that the source of the problem is the device_del() in pci_stop_dev() as it now causes the sysfs directory of the device to be removed recursively along with all of its subdirectories. That includes the sysfs directory of the device's subordinate bus (dev->subordinate) and its "power" group. Consequently, when pci_remove_bus() is called for dev->subordinate in pci_remove_bus_device(), it calls device_unregister(&bus->dev), but at this point the sysfs directory of bus->dev doesn't exist any more and its "power" group doesn't exist either. Thus, when dpm_sysfs_remove() called from device_del() tries to remove that group, it triggers the above warning. That indicates a logical mistake in the design of pci_stop_and_remove_bus_device(), which causes bus device objects to be left behind their parents (bridge device objects) and can be fixed by moving the device_del() from pci_stop_dev() into pci_destroy_dev(), so pci_remove_bus() can be called for the device's subordinate bus before the device itself is unregistered from the hierarchy. Still, the driver, if any, should be detached from the device in pci_stop_dev(), so use device_release_driver() directly from there. References: https://bugzilla.kernel.org/show_bug.cgi?id=65281#c6 Reported-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas --- diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 1576851028db..cc9337a71529 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -24,7 +24,7 @@ static void pci_stop_dev(struct pci_dev *dev) if (dev->is_added) { pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); - device_del(&dev->dev); + device_release_driver(&dev->dev); dev->is_added = 0; } @@ -34,6 +34,8 @@ static void pci_stop_dev(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev) { + device_del(&dev->dev); + down_write(&pci_bus_sem); list_del(&dev->bus_list); up_write(&pci_bus_sem);