From: Waiman Long <[email protected]> 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 <[email protected]>
> ---
>  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 <[email protected]>


Reply via email to