Skip to content

Commit 436f61a

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 11fc74d commit 436f61a

File tree

1 file changed

+10
-3
lines changed

1 file changed

+10
-3
lines changed

drivers/pci/controller/pci-hyperv.c

+10-3
Original file line numberDiff line numberDiff line change
@@ -3229,17 +3229,24 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
32293229
return 0;
32303230

32313231
if (!keep_devs) {
3232-
/* Delete any children which might still exist. */
3232+
struct list_head removed;
3233+
3234+
/* Move all present children to the list on stack */
3235+
INIT_LIST_HEAD(&removed);
32333236
spin_lock_irqsave(&hbus->device_list_lock, flags);
3234-
list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry) {
3237+
list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry)
3238+
list_move_tail(&hpdev->list_entry, &removed);
3239+
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
3240+
3241+
/* Remove all children in the list */
3242+
list_for_each_entry_safe(hpdev, tmp, &removed, list_entry) {
32353243
list_del(&hpdev->list_entry);
32363244
if (hpdev->pci_slot)
32373245
pci_destroy_slot(hpdev->pci_slot);
32383246
/* For the two refs got in new_pcichild_device() */
32393247
put_pcichild(hpdev);
32403248
put_pcichild(hpdev);
32413249
}
3242-
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
32433250
}
32443251

32453252
ret = hv_send_resources_released(hdev);

0 commit comments

Comments
 (0)