Skip to content

Commit 8aef382

Browse files
longlimsftgregkh
authored andcommitted
PCI: hv: Fix sleep while in non-sleep context when removing child devices from the bus
[ Upstream commit 41608b6 ] In hv_pci_bus_exit, the code is holding a spinlock while calling pci_destroy_slot(), which takes a mutex. This is not safe for spinlock. Fix this by moving the children to be deleted to a list on the stack, and removing them after spinlock is released. Fixes: 94d2276 ("PCI: hv: Fix a race condition when removing the device") Cc: "K. Y. Srinivasan" <[email protected]> Cc: Haiyang Zhang <[email protected]> Cc: Stephen Hemminger <[email protected]> Cc: Wei Liu <[email protected]> Cc: Dexuan Cui <[email protected]> Cc: Lorenzo Pieralisi <[email protected]> Cc: Rob Herring <[email protected]> Cc: "Krzysztof Wilczyński" <[email protected]> Cc: Bjorn Helgaas <[email protected]> Cc: Michael Kelley <[email protected]> Reported-by: Dan Carpenter <[email protected]> Link: https://lore.kernel.org/linux-hyperv/20210823152130.GA21501@kili/ Signed-off-by: Long Li <[email protected]> Reviewed-by: Wei Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent d9b838a commit 8aef382

File tree

1 file changed

+10
-3
lines changed

1 file changed

+10
-3
lines changed

drivers/pci/controller/pci-hyperv.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3259,17 +3259,24 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
32593259
return 0;
32603260

32613261
if (!keep_devs) {
3262-
/* Delete any children which might still exist. */
3262+
struct list_head removed;
3263+
3264+
/* Move all present children to the list on stack */
3265+
INIT_LIST_HEAD(&removed);
32633266
spin_lock_irqsave(&hbus->device_list_lock, flags);
3264-
list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry) {
3267+
list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry)
3268+
list_move_tail(&hpdev->list_entry, &removed);
3269+
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
3270+
3271+
/* Remove all children in the list */
3272+
list_for_each_entry_safe(hpdev, tmp, &removed, list_entry) {
32653273
list_del(&hpdev->list_entry);
32663274
if (hpdev->pci_slot)
32673275
pci_destroy_slot(hpdev->pci_slot);
32683276
/* For the two refs got in new_pcichild_device() */
32693277
put_pcichild(hpdev);
32703278
put_pcichild(hpdev);
32713279
}
3272-
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
32733280
}
32743281

32753282
ret = hv_send_resources_released(hdev);

0 commit comments

Comments
 (0)