[PATCH RFC 0/3] pci_hp: fix surprise removal hang during safe removal
Abhin Parekadan Jose <[email protected]>
| Newsgroups | dev.linux.lists.virtualization,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
This series is based on top of MST's RFC v5 ([email protected]) and tries to address the architectural gap identified by Lukas Wunner in that thread. Context: MST's RFC v5 adds disconnect_work infrastructure so drivers can be notified of surprise removal. Lukas identified a race that the series cannot address: if safe removal is already in progress when the device is yanked, pciehp_ist() is blocked and cannot deliver the disconnect event. Potential fix: I reproduced this with a simple edu device driver (patch 1) that blocks in remove() waiting for an interrupt. Same as blk_mq_freeze_queue_wait(). deadlock in pciehp_ist() is avoided by adding a workaround in pciehp_isr() (patch 3) where a disconnect_work is scheduled and as this is a different thread it runs and dispatches the disconnect event to the driver. The driver can then unblock and complete the remove() and thus breaking the deadlock and also overcoming the problem of not waiting in pciehp_isr().This is only schduled if the PDS is set to 0 indicating that there is no card attached at this slot in pciehp_isr(). Tested using qemu: - Hacked the edu device to raise a delayed interrupt. - Hacked qemu to actually act like suprise removal by adding a simple monitor cmd `pcie_surprise_del` to remove the device and genrate PDC=1, DLLSC = 1 and PDS=0. 1. Launched qemu with the edu device: `-device pcie-root-port,id=rp1,chassis=1,slot=1 -device edu,bus=rp1,id=edu0` 2. Ran `echo 1 > /sys/bus/pci/devices/0000:01:00.0/remove` to start safe removal 3. Ran `pcie_surprise_del edu0` to surprise remove the device while safe removal is in progress. 4. Verified that `edu_remove()` and `edu_disconnect()` are called. Without the fix: remove() hangs permanently. With the fix: pciehp_isr() fires, pciehp_disconnect_work() schedules pci_dev_set_disconnected(), edu_disconnect() completes the wait, remove() proceeds. Would this be a viable approach? Assisted-by: Claude:claude-sonnet-4-6 Abhin Parekadan Jose (3): misc: add edu_srpoc surprise removal POC driver pciehp: add disconnect_work work_struct pciehp_hpc: workaround to not wait in pciehp_isr on surprise removal drivers/misc/Makefile | 1 + drivers/misc/edu_srpoc.c | 180 +++++++++++++++++++++++++++++++ drivers/pci/hotplug/pciehp.h | 1 + drivers/pci/hotplug/pciehp_hpc.c | 47 ++++++++ 4 files changed, 229 insertions(+) create mode 100644 drivers/misc/edu_srpoc.c -- 2.51.1