Hej,
I stumbled over this lockdep splat during pci hotplug:
[ 26.016648] ======================================================
[ 26.019646] WARNING: possible circular locking dependency detected
[ 26.022785] 6.12.0-rc6+ #176 Not tainted
[ 26.024776] ------------------------------------------------------
[ 26.027909] irq/50-pciehp/57 is trying to acquire lock:
[ 26.030559] ffff0000c02ad700 (&ctrl->reset_lock){.+.+}-{3:3}, at: pciehp_configure_device+0xe4/0x1a0
[ 26.035423]
[ 26.035423] but task is already holding lock:
[ 26.038505] ffff800082f819f8 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x24/0x38
[ 26.043512]
[ 26.043512] which lock already depends on the new lock.
[ 26.043512]
[ 26.047863]
[ 26.047863] the existing dependency chain (in reverse order) is:
[ 26.051823]
[ 26.051823] -> #1 (pci_rescan_remove_lock){+.+.}-{3:3}:
[ 26.056209] __mutex_lock+0x90/0x3a0
[ 26.057946] mutex_lock_nested+0x2c/0x40
[ 26.059848] pci_lock_rescan_remove+0x24/0x38
[ 26.062560] pciehp_configure_device+0x48/0x1a0
[ 26.065592] pciehp_handle_presence_or_link_change+0x1e0/0x4a0
[ 26.069044] pciehp_ist+0x21c/0x268
[ 26.071186] irq_thread_fn+0x34/0xb8
[ 26.073368] irq_thread+0x154/0x2d0
[ 26.075503] kthread+0x108/0x120
[ 26.077504] ret_from_fork+0x10/0x20
[ 26.079695]
[ 26.079695] -> #0 (&ctrl->reset_lock){.+.+}-{3:3}:
[ 26.083164] __lock_acquire+0x12bc/0x1eb8
[ 26.085592] lock_acquire+0x1e0/0x358
[ 26.087831] down_read_nested+0x54/0x160
[ 26.090198] pciehp_configure_device+0xe4/0x1a0
[ 26.092895] pciehp_handle_presence_or_link_change+0x1e0/0x4a0
[ 26.096225] pciehp_ist+0x21c/0x268
[ 26.098337] irq_thread_fn+0x34/0xb8
[ 26.100509] irq_thread+0x154/0x2d0
[ 26.102668] kthread+0x108/0x120
[ 26.104660] ret_from_fork+0x10/0x20
[ 26.106790]
[ 26.106790] other info that might help us debug this:
[ 26.106790]
[ 26.111033] Possible unsafe locking scenario:
[ 26.111033]
[ 26.114184] CPU0 CPU1
[ 26.116607] ---- ----
[ 26.119023] lock(pci_rescan_remove_lock);
[ 26.121776] lock(&ctrl->reset_lock);
[ 26.123924] lock(pci_rescan_remove_lock);
[ 26.126098] rlock(&ctrl->reset_lock);
[ 26.127349]
[ 26.127349] *** DEADLOCK ***
[ 26.127349]
[ 26.129274] 1 lock held by irq/50-pciehp/57:
[ 26.130664] #0: ffff800082f819f8 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x24/0x38
[ 26.135941]
[ 26.135941] stack backtrace:
[ 26.138240] CPU: 0 UID: 0 PID: 57 Comm: irq/50-pciehp Not tainted 6.12.0-rc6+ #176
[ 26.142223] Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20230524-3.fc37 05/24/2023
[ 26.146514] Call trace:
[ 26.147795] dump_backtrace+0xa4/0x130
[ 26.149759] show_stack+0x20/0x38
[ 26.151504] dump_stack_lvl+0x90/0xd0
[ 26.153429] dump_stack+0x18/0x28
[ 26.155209] print_circular_bug+0x28c/0x370
[ 26.157601] check_noncircular+0x140/0x150
[ 26.159830] __lock_acquire+0x12bc/0x1eb8
[ 26.161949] lock_acquire+0x1e0/0x358
[ 26.163990] down_read_nested+0x54/0x160
[ 26.166172] pciehp_configure_device+0xe4/0x1a0
[ 26.168586] pciehp_handle_presence_or_link_change+0x1e0/0x4a0
[ 26.171755] pciehp_ist+0x21c/0x268
[ 26.173672] irq_thread_fn+0x34/0xb8
[ 26.175523] irq_thread+0x154/0x2d0
[ 26.177336] kthread+0x108/0x120
[ 26.179000] ret_from_fork+0x10/0x20
I don't think that this could actually happen since this is only called by a
single irq thread but this splat is kinda annoying and pciehp_configure_device()
doesn't seem to do much that needs the reset_lock. How about this?
---->8
[PATCH] pciehp: fix lockdep warning
Call pciehp_configure_device() without reset_lock being held to
fix the following lockdep warning. The only action that seems to
require the reset_lock is writing to ctrl->dsn, so move that to
the caller that holds the lock.
[ 26.019646] WARNING: possible circular locking dependency detected
[ 26.022785] 6.12.0-rc6+ #176 Not tainted
[ 26.024776] ------------------------------------------------------
[ 26.027909] irq/50-pciehp/57 is trying to acquire lock:
[ 26.030559] ffff0000c02ad700 (&ctrl->reset_lock){.+.+}-{3:3}, at: pciehp_configure_device+0xe4/0x1a0
[ 26.035423]
[ 26.035423] but task is already holding lock:
[ 26.038505] ffff800082f819f8 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x24/0x38
[ 26.043512]
[ 26.043512] which lock already depends on the new lock.
Signed-off-by: Sebastian Ott <sebott@xxxxxxxxxx>
---
drivers/pci/hotplug/pciehp.h | 2 +-
drivers/pci/hotplug/pciehp_ctrl.c | 11 ++++++++++-
drivers/pci/hotplug/pciehp_pci.c | 12 ++++--------
3 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 273dd8c66f4e..ff7651d9b49e 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -165,7 +165,7 @@ void pciehp_request(struct controller *ctrl, int action);
void pciehp_handle_button_press(struct controller *ctrl);
void pciehp_handle_disable_request(struct controller *ctrl);
void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events);
-int pciehp_configure_device(struct controller *ctrl);
+int pciehp_configure_device(struct controller *ctrl, u64 *dsn);
void pciehp_unconfigure_device(struct controller *ctrl, bool presence);
void pciehp_queue_pushbutton_work(struct work_struct *work);
struct controller *pcie_init(struct pcie_device *dev);
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index dcdbfcf404dd..ed0526bed16e 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -59,6 +59,7 @@ static void set_slot_off(struct controller *ctrl)
static int board_added(struct controller *ctrl)
{
int retval = 0;
+ u64 dsn = 0;
struct pci_bus *parent = ctrl->pcie->port->subordinate;
if (POWER_CTRL(ctrl)) {
@@ -83,13 +84,21 @@ static int board_added(struct controller *ctrl)
goto err_exit;
}
- retval = pciehp_configure_device(ctrl);
+ /*
+ * Release reset_lock during driver binding
+ * to avoid AB-BA deadlock with device_lock.
+ */
+ up_read(&ctrl->reset_lock);
+ retval = pciehp_configure_device(ctrl, &dsn);
+ down_read_nested(&ctrl->reset_lock, ctrl->depth);
if (retval) {
if (retval != -EEXIST) {
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
pci_domain_nr(parent), parent->number);
goto err_exit;
}
+ } else {
+ ctrl->dsn = dsn;
}
pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 65e50bee1a8c..9ef28c841c36 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -24,12 +24,14 @@
/**
* pciehp_configure_device() - enumerate PCI devices below a hotplug bridge
* @ctrl: PCIe hotplug controller
+ * @dsn: Device Serial Number of Function 0 in the hotplug slot
*
* Enumerate PCI devices below a hotplug bridge and add them to the system.
+ * On success store the Device Serial Number of Function 0 in @dsn.
* Return 0 on success, %-EEXIST if the devices are already enumerated or
* %-ENODEV if enumeration failed.
*/
-int pciehp_configure_device(struct controller *ctrl)
+int pciehp_configure_device(struct controller *ctrl, u64 *dsn)
{
struct pci_dev *dev;
struct pci_dev *bridge = ctrl->pcie->port;
@@ -64,16 +66,10 @@ int pciehp_configure_device(struct controller *ctrl)
pci_assign_unassigned_bridge_resources(bridge);
pcie_bus_configure_settings(parent);
- /*
- * Release reset_lock during driver binding
- * to avoid AB-BA deadlock with device_lock.
- */
- up_read(&ctrl->reset_lock);
pci_bus_add_devices(parent);
- down_read_nested(&ctrl->reset_lock, ctrl->depth);
dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
- ctrl->dsn = pci_get_dsn(dev);
+ *dsn = pci_get_dsn(dev);
pci_dev_put(dev);
out:
--
2.42.0