Re: [PATCH v2] PCI: hv: warn when wait_for_response() waits indefinitely
From: Naman Jain
Date: Thu Sep 03 2026 - 05:38:54 EST
On 9/3/2026 2:31 PM, Naman Jain wrote:
On 9/2/2026 5:28 PM, Sahil Chandna wrote:
A guest can wait indefinitely in wait_for_response() for the host to
send either a rescind message or a packet completion. If the
host does not send either, the guest can remain blocked with no
diagnostic indicating a reason.
This was observed during a guest kernel upgrade in which the
host-side application handling the PCI channel faulted, causing the
guest to never receive the completion request.
Add a warning in wait_for_response() when the wait exceeds
a timeout so that such a hang is visible in the guest's kernel log
and can be correlated with host-side state.
Suggested-by: Hamza Mahfooz <hamzamahfooz@xxxxxxxxxxxxxxxxxxx>
Suggested-by: Naman Jain <namjain@xxxxxxxxxxxxxxxxxxx>
Suggested-by: Michael Kelley <mhklinux@xxxxxxxxxxx>
These two tags can be omitted IMO.
Signed-off-by: Sahil Chandna <sahilchandna@xxxxxxxxxxxxxxxxxxx>
---
Changes since v1:
- Removed periodic warning to one time warning in 2 minutes
- Include vmbus relid and stuck PCI msg.
Link to v1: https://lore.kernel.org/all/20260825051850.2438816-1- sahilchandna@xxxxxxxxxxxxxxxxxxx/
---
drivers/pci/controller/pci-hyperv.c | 48 +++++++++++++++++++++++------
1 file changed, 38 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/ controller/pci-hyperv.c
index 89816a2bd7cd..ca9d8efd748c 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1040,19 +1040,40 @@ static void put_pcichild(struct hv_pci_dev *hpdev)
/*
* There is no good way to get notified from vmbus_onoffer_rescind(),
- * so let's use polling here, since this is not a hot path.
+ * so let's use polling here, since this is not a hot path. If
+ * wait_for_response() has been polling for PCI_RESPONSE_HANG_TIMEOUT_SEC
+ * without either a rescind or completion, add a warning.
*/
+#define PCI_RESPONSE_HANG_TIMEOUT_SEC 120
+
static int wait_for_response(struct hv_device *hdev,
- struct completion *comp)
+ struct completion *comp,
+ const char *msg_type)
{
+ unsigned long delay = secs_to_jiffies(PCI_RESPONSE_HANG_TIMEOUT_SEC);
+ u64 timeout = get_jiffies_64() + delay;
+ bool warned = false;
+
while (true) {
if (hdev->channel->rescind) {
dev_warn_once(&hdev->device, "The device is gone.\n");
return -ENODEV;
}
- if (wait_for_completion_timeout(comp, HZ / 10))
+ if (wait_for_completion_timeout(comp, HZ / 10)) {
+ if (warned)
+ dev_warn(&hdev->device,
+ "Late %s completion arrived.\n", msg_type);
break;
+ }
+
+ if (!warned && time_after64(get_jiffies_64(), timeout)) {
+ dev_err(&hdev->device,
+ "%s stuck waiting for response, relid = %u\n",
+ msg_type, hdev->channel->offermsg.child_relid);
+
+ warned = true;
+ }
}
return 0;
@@ -1518,7 +1539,8 @@ static int hv_read_config_block(struct pci_dev *pdev, void *buf,
if (ret)
return ret;
- ret = wait_for_response(hbus->hdev, &comp_pkt.comp_pkt.host_event);
+ ret = wait_for_response(hbus->hdev, &comp_pkt.comp_pkt.host_event,
+ "PCI_READ_BLOCK");
Instead of hard-coding this msg type two times everywhere, would it be better to simply pass corresponding variable.message_type.type?
You can ignore this, as you may have wanted to print actual name instead of enum value.
Regards,
Naman