RE: [PATCH v5] Drivers: hv: Avoid infinite retry loop in init_vp_index()

From: Michael Kelley

Date: Sun Aug 30 2026 - 21:25:31 EST


From: Waiman Long <longman@xxxxxxxxxx> Sent: Sunday, August 30, 2026 4:41 PM
>
> There is a retry loop in init_vp_index() where the CPUs from a certain
> node are stripped out if they have already been in the allocated cpumask
> or not in HK_TYPE_MANAGED_IRQ housekeeping cpumask. If there is no
> CPU left, the allocated cpumask is ignored and the process is retried
> again. However, if the HK_TYPE_MANAGED_IRQ housekeeping cpumask turns
> out not to contain any CPU in that particular node, that will become an
> infinite retry loop. This particular problem was reported by sashiko
> [1]. This should rarely happen, but we still need to guard against this.
>
> Fix this infinite loop problem by also skipping NUMA node that has no
> housekeeping CPU in the inner while loop of init_vp_index(). Also update
> the early abort check to check for the absence of online housekeeping
> CPUs instead of just the emptiness of the cpumask. As the outer for
> loop will only be reached if the housekeeping cpumask has at least one
> online CPU, a NUMA node with housekeeping CPUs will eventually be found.
>
> Link: https://sashiko.dev/#/message/20260422030903.E1BFCC2BCB0%40smtp.kernel.org [1]
> Fixes: 6640b5df1a38 ("Drivers: hv: vmbus: Don't assign VMbus channel interrupts to isolated CPUs")
> Signed-off-by: Waiman Long <longman@xxxxxxxxxx>
> ---
> drivers/hv/channel_mgmt.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
> index 89d214dda360..28b8ff9aea6e 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)) {
> --
> 2.55.0
>

Looks good.

Reviewed-by: Michael Kelley <mhkelley@xxxxxxxxxxx>