Skip to content

Commit 83cc350

Browse files
whu2014Lorenzo Pieralisi
authored andcommitted
PCI: hv: Fix the PCI HyperV probe failure path to release resource properly
In some error cases in hv_pci_probe(), allocated resources are not freed. Fix this by adding a field to keep track of the high water mark for slots that have resources allocated to them. In case of an error, this high water mark is used to know which slots have resources that must be released. Since slots are numbered starting with zero, a value of -1 indicates no slots have been allocated resources. There may be unused slots in the range between slot 0 and the high water mark slot, but these slots are already ignored by the existing code in the allocate and release loops with the call to get_pcichild_wslot(). Link: https://lore.kernel.org/r/20200507050211.10923-1-weh@microsoft.com Signed-off-by: Wei Hu <weh@microsoft.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Michael Kelley <mikelley@microsoft.com>
1 parent 8f3d9f3 commit 83cc350

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

drivers/pci/controller/pci-hyperv.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,9 @@ struct hv_pcibus_device {
480480

481481
struct workqueue_struct *wq;
482482

483+
/* Highest slot of child device with resources allocated */
484+
int wslot_res_allocated;
485+
483486
/* hypercall arg, must not cross page boundary */
484487
struct hv_retarget_device_interrupt retarget_msi_interrupt_params;
485488

@@ -2847,7 +2850,7 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
28472850
struct hv_pci_dev *hpdev;
28482851
struct pci_packet *pkt;
28492852
size_t size_res;
2850-
u32 wslot;
2853+
int wslot;
28512854
int ret;
28522855

28532856
size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2)
@@ -2900,6 +2903,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
29002903
comp_pkt.completion_status);
29012904
break;
29022905
}
2906+
2907+
hbus->wslot_res_allocated = wslot;
29032908
}
29042909

29052910
kfree(pkt);
@@ -2918,10 +2923,10 @@ static int hv_send_resources_released(struct hv_device *hdev)
29182923
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
29192924
struct pci_child_message pkt;
29202925
struct hv_pci_dev *hpdev;
2921-
u32 wslot;
2926+
int wslot;
29222927
int ret;
29232928

2924-
for (wslot = 0; wslot < 256; wslot++) {
2929+
for (wslot = hbus->wslot_res_allocated; wslot >= 0; wslot--) {
29252930
hpdev = get_pcichild_wslot(hbus, wslot);
29262931
if (!hpdev)
29272932
continue;
@@ -2936,8 +2941,12 @@ static int hv_send_resources_released(struct hv_device *hdev)
29362941
VM_PKT_DATA_INBAND, 0);
29372942
if (ret)
29382943
return ret;
2944+
2945+
hbus->wslot_res_allocated = wslot - 1;
29392946
}
29402947

2948+
hbus->wslot_res_allocated = -1;
2949+
29412950
return 0;
29422951
}
29432952

@@ -3037,6 +3046,7 @@ static int hv_pci_probe(struct hv_device *hdev,
30373046
if (!hbus)
30383047
return -ENOMEM;
30393048
hbus->state = hv_pcibus_init;
3049+
hbus->wslot_res_allocated = -1;
30403050

30413051
/*
30423052
* The PCI bus "domain" is what is called "segment" in ACPI and other
@@ -3136,7 +3146,7 @@ static int hv_pci_probe(struct hv_device *hdev,
31363146

31373147
ret = hv_pci_allocate_bridge_windows(hbus);
31383148
if (ret)
3139-
goto free_irq_domain;
3149+
goto exit_d0;
31403150

31413151
ret = hv_send_resources_allocated(hdev);
31423152
if (ret)
@@ -3154,6 +3164,8 @@ static int hv_pci_probe(struct hv_device *hdev,
31543164

31553165
free_windows:
31563166
hv_pci_free_bridge_windows(hbus);
3167+
exit_d0:
3168+
(void) hv_pci_bus_exit(hdev, true);
31573169
free_irq_domain:
31583170
irq_domain_remove(hbus->irq_domain);
31593171
free_fwnode:

0 commit comments

Comments
 (0)