Skip to content

Commit 5efbabe

Browse files
Gavin Shanozbenh
authored andcommitted
powerpc/pseries: Avoid deadlock on removing ddw
Function remove_ddw() could be called in of_reconfig_notifier and we potentially remove the dynamic DMA window property, which invokes of_reconfig_notifier again. Eventually, it leads to the deadlock as following backtrace shows. The patch fixes the above issue by deferring releasing the dynamic DMA window property while releasing the device node. ============================================= [ INFO: possible recursive locking detected ] 3.16.0+ torvalds#428 Tainted: G W --------------------------------------------- drmgr/2273 is trying to acquire lock: ((of_reconfig_chain).rwsem){.+.+..}, at: [<c000000000091890>] \ .__blocking_notifier_call_chain+0x40/0x78 but task is already holding lock: ((of_reconfig_chain).rwsem){.+.+..}, at: [<c000000000091890>] \ .__blocking_notifier_call_chain+0x40/0x78 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock((of_reconfig_chain).rwsem); lock((of_reconfig_chain).rwsem); *** DEADLOCK *** May be due to missing lock nesting notation 2 locks held by drmgr/2273: #0: (sb_writers#4){.+.+.+}, at: [<c0000000001cbe70>] \ .vfs_write+0xb0/0x1f8 #1: ((of_reconfig_chain).rwsem){.+.+..}, at: [<c000000000091890>] \ .__blocking_notifier_call_chain+0x40/0x78 stack backtrace: CPU: 17 PID: 2273 Comm: drmgr Tainted: G W 3.16.0+ torvalds#428 Call Trace: [c0000000137e7000] [c000000000013d9c] .show_stack+0x88/0x148 (unreliable) [c0000000137e70b0] [c00000000083cd34] .dump_stack+0x7c/0x9c [c0000000137e7130] [c0000000000b8afc] .__lock_acquire+0x128c/0x1c68 [c0000000137e7280] [c0000000000b9a4c] .lock_acquire+0xe8/0x104 [c0000000137e7350] [c00000000083588c] .down_read+0x4c/0x90 [c0000000137e73e0] [c000000000091890] .__blocking_notifier_call_chain+0x40/0x78 [c0000000137e7490] [c000000000091900] .blocking_notifier_call_chain+0x38/0x48 [c0000000137e7520] [c000000000682a28] .of_reconfig_notify+0x34/0x5c [c0000000137e75b0] [c000000000682a9c] .of_property_notify+0x4c/0x54 [c0000000137e7650] [c000000000682bf0] .of_remove_property+0x30/0xd4 [c0000000137e76f0] [c000000000052a44] .remove_ddw+0x144/0x168 [c0000000137e7790] [c000000000053204] .iommu_reconfig_notifier+0x30/0xe0 [c0000000137e7820] [c00000000009137c] .notifier_call_chain+0x6c/0xb4 [c0000000137e78c0] [c0000000000918ac] .__blocking_notifier_call_chain+0x5c/0x78 [c0000000137e7970] [c000000000091900] .blocking_notifier_call_chain+0x38/0x48 [c0000000137e7a00] [c000000000682a28] .of_reconfig_notify+0x34/0x5c [c0000000137e7a90] [c000000000682e14] .of_detach_node+0x44/0x1fc [c0000000137e7b40] [c0000000000518e4] .ofdt_write+0x3ac/0x688 [c0000000137e7c20] [c000000000238430] .proc_reg_write+0xb8/0xd4 [c0000000137e7cd0] [c0000000001cbeac] .vfs_write+0xec/0x1f8 [c0000000137e7d70] [c0000000001cc3b0] .SyS_write+0x58/0xa0 [c0000000137e7e30] [c00000000000a064] syscall_exit+0x0/0x98 Cc: [email protected] Signed-off-by: Gavin Shan <[email protected]> Signed-off-by: Benjamin Herrenschmidt <[email protected]>
1 parent f1b3929 commit 5efbabe

File tree

1 file changed

+14
-6
lines changed
  • arch/powerpc/platforms/pseries

1 file changed

+14
-6
lines changed

arch/powerpc/platforms/pseries/iommu.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -721,13 +721,13 @@ static int __init disable_ddw_setup(char *str)
721721

722722
early_param("disable_ddw", disable_ddw_setup);
723723

724-
static void remove_ddw(struct device_node *np)
724+
static void remove_ddw(struct device_node *np, bool remove_prop)
725725
{
726726
struct dynamic_dma_window_prop *dwp;
727727
struct property *win64;
728728
const u32 *ddw_avail;
729729
u64 liobn;
730-
int len, ret;
730+
int len, ret = 0;
731731

732732
ddw_avail = of_get_property(np, "ibm,ddw-applicable", &len);
733733
win64 = of_find_property(np, DIRECT64_PROPNAME, NULL);
@@ -761,7 +761,8 @@ static void remove_ddw(struct device_node *np)
761761
np->full_name, ret, ddw_avail[2], liobn);
762762

763763
delprop:
764-
ret = of_remove_property(np, win64);
764+
if (remove_prop)
765+
ret = of_remove_property(np, win64);
765766
if (ret)
766767
pr_warning("%s: failed to remove direct window property: %d\n",
767768
np->full_name, ret);
@@ -805,7 +806,7 @@ static int find_existing_ddw_windows(void)
805806
window = kzalloc(sizeof(*window), GFP_KERNEL);
806807
if (!window || len < sizeof(struct dynamic_dma_window_prop)) {
807808
kfree(window);
808-
remove_ddw(pdn);
809+
remove_ddw(pdn, true);
809810
continue;
810811
}
811812

@@ -1045,7 +1046,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
10451046
kfree(window);
10461047

10471048
out_clear_window:
1048-
remove_ddw(pdn);
1049+
remove_ddw(pdn, true);
10491050

10501051
out_free_prop:
10511052
kfree(win64->name);
@@ -1255,7 +1256,14 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
12551256

12561257
switch (action) {
12571258
case OF_RECONFIG_DETACH_NODE:
1258-
remove_ddw(np);
1259+
/*
1260+
* Removing the property will invoke the reconfig
1261+
* notifier again, which causes dead-lock on the
1262+
* read-write semaphore of the notifier chain. So
1263+
* we have to remove the property when releasing
1264+
* the device node.
1265+
*/
1266+
remove_ddw(np, false);
12591267
if (pci && pci->iommu_table)
12601268
iommu_free_table(pci->iommu_table, np->full_name);
12611269

0 commit comments

Comments
 (0)