summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-15 08:06:26 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-15 08:06:26 -0700
commit6a66840a68683d9361a9b31faf3bd8104428ad29 (patch)
tree0033c284126c9ba3445b06bdb52281f9cd864d77
parent9fee1f650a0a9ea6fa7c0b26244a778dd92542d5 (diff)
parentdbc393f6f009a2bf7e4a22ef2d70b53f533f20f4 (diff)
Merge tag 'hyperv-fixes-signed-20261015' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull Hyper-V fixes from Wei Liu: - Typo and comment fixes (Hemanth Selam, Jiangshan Yi) - Update maintainers list (Wei Liu, Long Li) - Two Hyper-V PCI driver fixes (Naman Jain, Sahil Chandna) - Small fixes for core Hyper-V code (Hardik Garg, Michael Kelley, Waiman Long) * tag 'hyperv-fixes-signed-20261015' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: MAINTAINERS: drop KY from Hyper-V maintainers list PCI: hv: Warn when wait_for_response() waits indefinitely PCI: hv: Probe vPCI buses asynchronously MAINTAINERS: remove myself from the Hyper-V entries mshv_vtl: Check per-CPU register page before mmap tools/hv: fix typo "retrive" in comment Drivers: hv: vmbus: fix typo "substract" in comment Drivers: hv: Don't reset VMBus connection state on error/exit paths x86/hyperv: Avoid using per-cpu output page in hv_apicid_to_vp_index() x86/hyperv: Fix stale comments after stimer message mode removal Drivers: hv: Avoid infinite retry loop in init_vp_index()
-rw-r--r--MAINTAINERS3
-rw-r--r--arch/x86/hyperv/hv_init.c7
-rw-r--r--drivers/hv/channel.c2
-rw-r--r--drivers/hv/channel_mgmt.c12
-rw-r--r--drivers/hv/connection.c1
-rw-r--r--drivers/hv/mshv_vtl_main.c3
-rw-r--r--drivers/hv/vmbus_drv.c19
-rw-r--r--drivers/pci/controller/pci-hyperv.c49
-rwxr-xr-xtools/hv/hv_get_dns_info.sh2
9 files changed, 64 insertions, 34 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index f53047aa8d3c..c39194e896be 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8170,7 +8170,6 @@ F: drivers/gpu/drm/tiny/hx8357d.c
DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE
M: Dexuan Cui <decui@microsoft.com>
-M: Long Li <longli@microsoft.com>
M: Saurabh Sengar <ssengar@linux.microsoft.com>
L: linux-hyperv@vger.kernel.org
L: dri-devel@lists.freedesktop.org
@@ -12161,11 +12160,9 @@ S: Maintained
F: drivers/media/i2c/hi847.c
Hyper-V/Azure CORE AND DRIVERS
-M: "K. Y. Srinivasan" <kys@microsoft.com>
M: Haiyang Zhang <haiyangz@microsoft.com>
M: Wei Liu <wei.liu@kernel.org>
M: Dexuan Cui <decui@microsoft.com>
-M: Long Li <longli@microsoft.com>
L: linux-hyperv@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index 0b4a1c0b0b16..9900a5c59fd3 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -426,7 +426,7 @@ static void __init hv_stimer_setup_percpu_clockev(void)
int ret;
/*
- * Continue afters errors in setting up stimer clockevents
+ * Continue after errors in setting up stimer clockevents
* as we can run with the LAPIC timer as a fallback.
*/
ret = hv_stimer_alloc(false);
@@ -434,7 +434,7 @@ static void __init hv_stimer_setup_percpu_clockev(void)
pr_warn("stimer setup failed with error %d\n", ret);
/*
- * Still register the LAPIC timer to allows users
+ * Still register the LAPIC timer to allow users
* to switch to LAPIC timer via /sys, if they want to.
*/
if (old_setup_percpu_clockev)
@@ -727,7 +727,8 @@ int hv_apicid_to_vp_index(u32 apic_id)
input->partition_id = HV_PARTITION_ID_SELF;
input->apic_ids[0] = apic_id;
- output = *this_cpu_ptr(hyperv_pcpu_output_arg);
+ /* Treat input as having 2 APIC IDs so output is 64-bit aligned */
+ output = (void *)input + struct_size(input, apic_ids, 2);
control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_INDEX_FROM_APIC_ID;
status = hv_do_hypercall(control, input, output);
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 7e4cc6f55237..a0883ddf32e2 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -79,7 +79,7 @@ static inline u32 hv_ring_gpadl_send_hvpgoffset(u32 offset)
* therefore leaving a (PAGE_SIZE - HV_HYP_PAGE_SIZE) gap.
*
* And to calculate the effective send offset in gpadl, we need to
- * substract this gap.
+ * subtract this gap.
*/
return (offset - (PAGE_SIZE - HV_HYP_PAGE_SIZE)) >> HV_HYP_PAGE_SHIFT;
}
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index a044fd3b3c4e..c42def04ac41 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -752,13 +752,14 @@ static void init_vp_index(struct vmbus_channel *channel)
u32 i, ncpu = num_online_cpus();
cpumask_var_t available_mask;
struct cpumask *allocated_mask;
+ const struct cpumask *node_mask;
const struct cpumask *hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ);
u32 target_cpu;
int numa_node;
if (!perf_chn ||
!alloc_cpumask_var(&available_mask, GFP_KERNEL) ||
- cpumask_empty(hk_mask)) {
+ !cpumask_intersects(hk_mask, cpu_online_mask)) {
/*
* If the channel is not a performance critical
* channel, bind it to VMBUS_CONNECT_CPU.
@@ -780,14 +781,19 @@ static void init_vp_index(struct vmbus_channel *channel)
next_numa_node_id = 0;
continue;
}
- if (cpumask_empty(cpumask_of_node(numa_node)))
+ /*
+ * Try next NUMA node if current NUMA node has no CPU
+ * or doesn't contain any housekeeping CPU.
+ */
+ node_mask = cpumask_of_node(numa_node);
+ if (!cpumask_intersects(node_mask, hk_mask))
continue;
break;
}
allocated_mask = &hv_context.hv_numa_map[numa_node];
retry:
- cpumask_xor(available_mask, allocated_mask, cpumask_of_node(numa_node));
+ cpumask_xor(available_mask, allocated_mask, node_mask);
cpumask_and(available_mask, available_mask, hk_mask);
if (cpumask_empty(available_mask)) {
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 1ab3581b096a..818667ef9c74 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -346,7 +346,6 @@ int vmbus_connect(void)
cleanup:
pr_err("Unable to connect to host\n");
- vmbus_connection.conn_state = DISCONNECTED;
vmbus_disconnect();
kfree(msginfo);
diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c
index 6e3c11c68171..d8225242c73f 100644
--- a/drivers/hv/mshv_vtl_main.c
+++ b/drivers/hv/mshv_vtl_main.c
@@ -819,6 +819,9 @@ static vm_fault_t mshv_vtl_fault(struct vm_fault *vmf)
return VM_FAULT_NOPAGE;
}
+ if (!page)
+ return VM_FAULT_SIGBUS;
+
get_page(page);
vmf->page = page;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 5ebdbe24b5a1..4692687cdbf3 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -2923,23 +2923,19 @@ static void hv_crash_handler(struct pt_regs *regs)
static int hv_synic_suspend(void *data)
{
/*
- * When we reach here, all the non-boot CPUs have been offlined.
- * If we're in a legacy configuration where stimer Direct Mode is
- * not enabled, the stimers on the non-boot CPUs have been unbound
- * in hv_synic_cleanup() -> hv_stimer_legacy_cleanup() ->
- * hv_stimer_cleanup() -> clockevents_unbind_device().
+ * When we reach here, all the non-boot CPUs have been offlined,
+ * and their stimers have been cleaned up by the cpuhp teardown
+ * callback hv_stimer_cleanup().
*
* hv_synic_suspend() only runs on CPU0 with interrupts disabled.
- * Here we do not call hv_stimer_legacy_cleanup() on CPU0 because:
- * 1) it's unnecessary as interrupts remain disabled between
- * syscore_suspend() and syscore_resume(): see create_image() and
+ * The stimer on CPU0 is not explicitly cleaned up here because:
+ * 1) it's harmless as interrupts remain disabled between
+ * syscore_suspend() and syscore_resume(), so the stimer cannot
+ * fire during this window: see create_image() and
* resume_target_kernel()
* 2) the stimer on CPU0 is automatically disabled later by
* syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ...
* -> clockevents_shutdown() -> ... -> hv_ce_shutdown()
- * 3) a warning would be triggered if we call
- * clockevents_unbind_device(), which may sleep, in an
- * interrupts-disabled context.
*/
hv_hyp_synic_disable_regs(0);
@@ -3043,7 +3039,6 @@ static void __exit vmbus_exit(void)
hv_remove_kexec_handler();
hv_remove_crash_handler();
- vmbus_connection.conn_state = DISCONNECTED;
hv_stimer_global_cleanup();
vmbus_disconnect();
if (vmbus_irq == -1)
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 89816a2bd7cd..85d826f8f68d 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1040,19 +1040,38 @@ 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 2 minutes
+ * without either a rescind or completion, add a warning.
*/
+#define PCI_RESPONSE_WARN_POLL_COUNT 1200
+
static int wait_for_response(struct hv_device *hdev,
- struct completion *comp)
+ struct completion *comp,
+ const char *msg_type)
{
+ u64 counter = 0;
+
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))
+ counter++;
+
+ if (wait_for_completion_timeout(comp, HZ / 10)) {
+ if (counter > PCI_RESPONSE_WARN_POLL_COUNT)
+ dev_warn(&hdev->device,
+ "Late %s completion arrived.\n", msg_type);
break;
+ }
+
+ if (counter == PCI_RESPONSE_WARN_POLL_COUNT) {
+ dev_err(&hdev->device,
+ "%s stuck waiting for response, relid = %u\n",
+ msg_type, hdev->channel->offermsg.child_relid);
+ }
}
return 0;
@@ -1518,7 +1537,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");
if (ret)
return ret;
@@ -1607,7 +1627,8 @@ static int hv_write_config_block(struct pci_dev *pdev, void *buf,
if (ret)
return ret;
- ret = wait_for_response(hbus->hdev, &comp_pkt.host_event);
+ ret = wait_for_response(hbus->hdev, &comp_pkt.host_event,
+ "PCI_WRITE_BLOCK");
if (ret)
return ret;
@@ -2624,7 +2645,8 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
if (ret)
goto error;
- if (wait_for_response(hbus->hdev, &comp_pkt.host_event))
+ if (wait_for_response(hbus->hdev, &comp_pkt.host_event,
+ "PCI_QUERY_RESOURCE_REQUIREMENTS"))
goto error;
hpdev->desc = *desc;
@@ -3256,7 +3278,8 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev,
(unsigned long)pkt, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (!ret)
- ret = wait_for_response(hdev, &comp_pkt.host_event);
+ ret = wait_for_response(hdev, &comp_pkt.host_event,
+ "PCI_QUERY_PROTOCOL_VERSION");
if (ret) {
dev_err(&hdev->device,
@@ -3476,7 +3499,8 @@ enter_d0_retry:
(unsigned long)pkt, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (!ret)
- ret = wait_for_response(hdev, &comp_pkt.host_event);
+ ret = wait_for_response(hdev, &comp_pkt.host_event,
+ "PCI_BUS_D0ENTRY");
if (ret)
goto exit;
@@ -3553,7 +3577,8 @@ 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)
- ret = wait_for_response(hdev, &comp);
+ ret = wait_for_response(hdev, &comp,
+ "PCI_QUERY_BUS_RELATIONS");
/*
* In the case of fast device addition/removal, it's possible that
@@ -3644,7 +3669,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (!ret)
- ret = wait_for_response(hdev, &comp_pkt.host_event);
+ ret = wait_for_response(hdev, &comp_pkt.host_event,
+ "PCI_RESOURCE_ASSIGNED");
if (ret)
break;
@@ -4155,6 +4181,9 @@ static struct hv_driver hv_pci_drv = {
.remove = hv_pci_remove,
.suspend = hv_pci_suspend,
.resume = hv_pci_resume,
+ .driver = {
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
};
static void __exit exit_hv_pci_drv(void)
diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh
index 268521234d4b..288821565eee 100755
--- a/tools/hv/hv_get_dns_info.sh
+++ b/tools/hv/hv_get_dns_info.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-# This example script parses /etc/resolv.conf to retrive DNS information.
+# This example script parses /etc/resolv.conf to retrieve DNS information.
# In the interest of keeping the KVP daemon code free of distro specific
# information; the kvp daemon code invokes this external script to gather
# DNS information.