Skip to content

Commit

Permalink
PCI: hv: Do not wait forever on a device that has disappeared
Browse files Browse the repository at this point in the history
commit c3635da upstream.

Before the guest finishes the device initialization, the device can be
removed anytime by the host, and after that the host won't respond to
the guest's request, so the guest should be prepared to handle this
case.

Add a polling mechanism to detect device presence.

Signed-off-by: Dexuan Cui <decui@microsoft.com>
[lorenzo.pieralisi@arm.com: edited commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Dexuan Cui authored and Greg Kroah-Hartman committed Jun 11, 2018
1 parent 5bc3be4 commit 517f981
Showing 1 changed file with 34 additions and 12 deletions.
46 changes: 34 additions & 12 deletions drivers/pci/host/pci-hyperv.c
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,26 @@ static void put_pcichild(struct hv_pci_dev *hv_pcidev,
static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);

/*
* 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.
*/
static int wait_for_response(struct hv_device *hdev,
struct completion *comp)
{
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))
break;
}

return 0;
}

/**
* devfn_to_wslot() - Convert from Linux PCI slot to Windows
* @devfn: The Linux representation of PCI slot
Expand Down Expand Up @@ -1568,7 +1588,8 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
if (ret)
goto error;

wait_for_completion(&comp_pkt.host_event);
if (wait_for_response(hbus->hdev, &comp_pkt.host_event))
goto error;

hpdev->desc = *desc;
refcount_set(&hpdev->refs, 1);
Expand Down Expand Up @@ -2061,15 +2082,16 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev)
sizeof(struct pci_version_request),
(unsigned long)pkt, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (!ret)
ret = wait_for_response(hdev, &comp_pkt.host_event);

if (ret) {
dev_err(&hdev->device,
"PCI Pass-through VSP failed sending version reqquest: %#x",
"PCI Pass-through VSP failed to request version: %d",
ret);
goto exit;
}

wait_for_completion(&comp_pkt.host_event);

if (comp_pkt.completion_status >= 0) {
pci_protocol_version = pci_protocol_versions[i];
dev_info(&hdev->device,
Expand Down Expand Up @@ -2278,11 +2300,12 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
ret = vmbus_sendpacket(hdev->channel, d0_entry, sizeof(*d0_entry),
(unsigned long)pkt, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (!ret)
ret = wait_for_response(hdev, &comp_pkt.host_event);

if (ret)
goto exit;

wait_for_completion(&comp_pkt.host_event);

if (comp_pkt.completion_status < 0) {
dev_err(&hdev->device,
"PCI Pass-through VSP failed D0 Entry with status %x\n",
Expand Down Expand Up @@ -2322,11 +2345,10 @@ static int hv_pci_query_relations(struct hv_device *hdev)

ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message),
0, VM_PKT_DATA_INBAND, 0);
if (ret)
return ret;
if (!ret)
ret = wait_for_response(hdev, &comp);

wait_for_completion(&comp);
return 0;
return ret;
}

/**
Expand Down Expand Up @@ -2396,11 +2418,11 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
size_res, (unsigned long)pkt,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (!ret)
ret = wait_for_response(hdev, &comp_pkt.host_event);
if (ret)
break;

wait_for_completion(&comp_pkt.host_event);

if (comp_pkt.completion_status < 0) {
ret = -EPROTO;
dev_err(&hdev->device,
Expand Down

0 comments on commit 517f981

Please sign in to comment.