Commit b4927bd2 authored by Andrea Parri (Microsoft)'s avatar Andrea Parri (Microsoft) Committed by Wei Liu
Browse files

PCI: hv: Fix synchronization between channel callback and hv_pci_bus_exit()



[ Similarly to commit a765ed47 ("PCI: hv: Fix synchronization
  between channel callback and hv_compose_msi_msg()"): ]

The (on-stack) teardown packet becomes invalid once the completion
timeout in hv_pci_bus_exit() has expired and hv_pci_bus_exit() has
returned.  Prevent the channel callback from accessing the invalid
packet by removing the ID associated to such packet from the VMbus
requestor in hv_pci_bus_exit().

Signed-off-by: default avatarAndrea Parri (Microsoft) <parri.andrea@gmail.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
Acked-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Link: https://lore.kernel.org/r/20220511223207.3386-3-parri.andrea@gmail.com


Signed-off-by: default avatarWei Liu <wei.liu@kernel.org>
parent 9937fa6d
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -3664,6 +3664,7 @@ static int hv_pci_probe(struct hv_device *hdev,
static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
{
	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
	struct vmbus_channel *chan = hdev->channel;
	struct {
		struct pci_packet teardown_packet;
		u8 buffer[sizeof(struct pci_message)];
@@ -3671,13 +3672,14 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
	struct hv_pci_compl comp_pkt;
	struct hv_pci_dev *hpdev, *tmp;
	unsigned long flags;
	u64 trans_id;
	int ret;

	/*
	 * After the host sends the RESCIND_CHANNEL message, it doesn't
	 * access the per-channel ringbuffer any longer.
	 */
	if (hdev->channel->rescind)
	if (chan->rescind)
		return 0;

	if (!keep_devs) {
@@ -3714,16 +3716,26 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
	pkt.teardown_packet.compl_ctxt = &comp_pkt;
	pkt.teardown_packet.message[0].type = PCI_BUS_D0EXIT;

	ret = vmbus_sendpacket(hdev->channel, &pkt.teardown_packet.message,
	ret = vmbus_sendpacket_getid(chan, &pkt.teardown_packet.message,
				     sizeof(struct pci_message),
				     (unsigned long)&pkt.teardown_packet,
			       VM_PKT_DATA_INBAND,
				     &trans_id, VM_PKT_DATA_INBAND,
				     VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
	if (ret)
		return ret;

	if (wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ) == 0)
	if (wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ) == 0) {
		/*
		 * The completion packet on the stack becomes invalid after
		 * 'return'; remove the ID from the VMbus requestor if the
		 * identifier is still mapped to/associated with the packet.
		 *
		 * Cf. hv_pci_onchannelcallback().
		 */
		vmbus_request_addr_match(chan, trans_id,
					 (unsigned long)&pkt.teardown_packet);
		return -ETIMEDOUT;
	}

	return 0;
}