diff mbox series

[v3,07/15] x86/IRQ: target online CPUs when binding guest IRQ

Message ID 5CDE917502000078002300A8@prv1-mh.provo.novell.com (mailing list archive)
State New, archived
Headers show
Series x86: IRQ management adjustments | expand

Commit Message

Jan Beulich May 17, 2019, 10:48 a.m. UTC
fixup_irqs() skips interrupts without action. Hence such interrupts can
retain affinity to just offline CPUs. With "noirqbalance" in effect,
pirq_guest_bind() so far would have left them alone, resulting in a non-
working interrupt.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v3: New.
---
I've not observed this problem in practice - the change is just the
result of code inspection after having noticed action-less IRQs in 'i'
debug key output pointing at all parked/offline CPUs.

Comments

Roger Pau Monne May 20, 2019, 11:40 a.m. UTC | #1
On Fri, May 17, 2019 at 04:48:21AM -0600, Jan Beulich wrote:
> fixup_irqs() skips interrupts without action. Hence such interrupts can
> retain affinity to just offline CPUs. With "noirqbalance" in effect,
> pirq_guest_bind() so far would have left them alone, resulting in a non-
> working interrupt.
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> ---
> v3: New.
> ---
> I've not observed this problem in practice - the change is just the
> result of code inspection after having noticed action-less IRQs in 'i'
> debug key output pointing at all parked/offline CPUs.
> 
> --- a/xen/arch/x86/irq.c
> +++ b/xen/arch/x86/irq.c
> @@ -1683,9 +1683,27 @@ int pirq_guest_bind(struct vcpu *v, stru
>  
>          desc->status |= IRQ_GUEST;
>  
> -        /* Attempt to bind the interrupt target to the correct CPU. */
> -        if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )
> -            desc->handler->set_affinity(desc, cpumask_of(v->processor));
> +        /*
> +         * Attempt to bind the interrupt target to the correct (or at least
> +         * some online) CPU.
> +         */
> +        if ( desc->handler->set_affinity )
> +        {
> +            const cpumask_t *affinity = NULL;
> +
> +            if ( !opt_noirqbalance )
> +                affinity = cpumask_of(v->processor);
> +            else if ( !cpumask_intersects(desc->affinity, &cpu_online_map) )
> +            {
> +                cpumask_setall(desc->affinity);
> +                affinity = &cpumask_all;
> +            }
> +            else if ( !cpumask_intersects(desc->arch.cpu_mask,
> +                                          &cpu_online_map) )

I'm not sure I see the purpose of the desc->arch.cpu_mask check,
wouldn't it be better to just use else and set the affinity to
desc->affinity?

Or it's just an optimization to avoid doing the set_affinity call if
the interrupt it already bound to an online CPU?

Thanks, Roger.
Jan Beulich May 20, 2019, 3:17 p.m. UTC | #2
>>> On 20.05.19 at 13:40, <roger.pau@citrix.com> wrote:
> On Fri, May 17, 2019 at 04:48:21AM -0600, Jan Beulich wrote:
>> fixup_irqs() skips interrupts without action. Hence such interrupts can
>> retain affinity to just offline CPUs. With "noirqbalance" in effect,
>> pirq_guest_bind() so far would have left them alone, resulting in a non-
>> working interrupt.
>> 
>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>> ---
>> v3: New.
>> ---
>> I've not observed this problem in practice - the change is just the
>> result of code inspection after having noticed action-less IRQs in 'i'
>> debug key output pointing at all parked/offline CPUs.
>> 
>> --- a/xen/arch/x86/irq.c
>> +++ b/xen/arch/x86/irq.c
>> @@ -1683,9 +1683,27 @@ int pirq_guest_bind(struct vcpu *v, stru
>>  
>>          desc->status |= IRQ_GUEST;
>>  
>> -        /* Attempt to bind the interrupt target to the correct CPU. */
>> -        if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )
>> -            desc->handler->set_affinity(desc, cpumask_of(v->processor));
>> +        /*
>> +         * Attempt to bind the interrupt target to the correct (or at least
>> +         * some online) CPU.
>> +         */
>> +        if ( desc->handler->set_affinity )
>> +        {
>> +            const cpumask_t *affinity = NULL;
>> +
>> +            if ( !opt_noirqbalance )
>> +                affinity = cpumask_of(v->processor);
>> +            else if ( !cpumask_intersects(desc->affinity, &cpu_online_map) )
>> +            {
>> +                cpumask_setall(desc->affinity);
>> +                affinity = &cpumask_all;
>> +            }
>> +            else if ( !cpumask_intersects(desc->arch.cpu_mask,
>> +                                          &cpu_online_map) )
> 
> I'm not sure I see the purpose of the desc->arch.cpu_mask check,
> wouldn't it be better to just use else and set the affinity to
> desc->affinity?

We should avoid clobbering desc->affinity whenever possible: It
reflects (see the respective patch in this series) what was
requested by whatever "outside" party.

> Or it's just an optimization to avoid doing the set_affinity call if
> the interrupt it already bound to an online CPU?

This is a second aspect here indeed - why play with the IRQ if
it has a valid destination?

Jan
Roger Pau Monne May 22, 2019, 9:41 a.m. UTC | #3
On Mon, May 20, 2019 at 09:17:19AM -0600, Jan Beulich wrote:
> >>> On 20.05.19 at 13:40, <roger.pau@citrix.com> wrote:
> > On Fri, May 17, 2019 at 04:48:21AM -0600, Jan Beulich wrote:
> >> fixup_irqs() skips interrupts without action. Hence such interrupts can
> >> retain affinity to just offline CPUs. With "noirqbalance" in effect,
> >> pirq_guest_bind() so far would have left them alone, resulting in a non-
> >> working interrupt.
> >> 
> >> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> >> ---
> >> v3: New.
> >> ---
> >> I've not observed this problem in practice - the change is just the
> >> result of code inspection after having noticed action-less IRQs in 'i'
> >> debug key output pointing at all parked/offline CPUs.
> >> 
> >> --- a/xen/arch/x86/irq.c
> >> +++ b/xen/arch/x86/irq.c
> >> @@ -1683,9 +1683,27 @@ int pirq_guest_bind(struct vcpu *v, stru
> >>  
> >>          desc->status |= IRQ_GUEST;
> >>  
> >> -        /* Attempt to bind the interrupt target to the correct CPU. */
> >> -        if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )
> >> -            desc->handler->set_affinity(desc, cpumask_of(v->processor));
> >> +        /*
> >> +         * Attempt to bind the interrupt target to the correct (or at least
> >> +         * some online) CPU.
> >> +         */
> >> +        if ( desc->handler->set_affinity )
> >> +        {
> >> +            const cpumask_t *affinity = NULL;
> >> +
> >> +            if ( !opt_noirqbalance )
> >> +                affinity = cpumask_of(v->processor);
> >> +            else if ( !cpumask_intersects(desc->affinity, &cpu_online_map) )
> >> +            {
> >> +                cpumask_setall(desc->affinity);
> >> +                affinity = &cpumask_all;
> >> +            }
> >> +            else if ( !cpumask_intersects(desc->arch.cpu_mask,
> >> +                                          &cpu_online_map) )
> > 
> > I'm not sure I see the purpose of the desc->arch.cpu_mask check,
> > wouldn't it be better to just use else and set the affinity to
> > desc->affinity?
> 
> We should avoid clobbering desc->affinity whenever possible: It
> reflects (see the respective patch in this series) what was
> requested by whatever "outside" party.
> 
> > Or it's just an optimization to avoid doing the set_affinity call if
> > the interrupt it already bound to an online CPU?
> 
> This is a second aspect here indeed - why play with the IRQ if
> it has a valid destination?

Thanks for the clarification, that LGTM:

Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>

Roger.
Andrew Cooper July 3, 2019, 6:30 p.m. UTC | #4
On 17/05/2019 11:48, Jan Beulich wrote:
> fixup_irqs() skips interrupts without action. Hence such interrupts can
> retain affinity to just offline CPUs. With "noirqbalance" in effect,
> pirq_guest_bind() so far would have left them alone, resulting in a non-
> working interrupt.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
diff mbox series

Patch

--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -1683,9 +1683,27 @@  int pirq_guest_bind(struct vcpu *v, stru
 
         desc->status |= IRQ_GUEST;
 
-        /* Attempt to bind the interrupt target to the correct CPU. */
-        if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )
-            desc->handler->set_affinity(desc, cpumask_of(v->processor));
+        /*
+         * Attempt to bind the interrupt target to the correct (or at least
+         * some online) CPU.
+         */
+        if ( desc->handler->set_affinity )
+        {
+            const cpumask_t *affinity = NULL;
+
+            if ( !opt_noirqbalance )
+                affinity = cpumask_of(v->processor);
+            else if ( !cpumask_intersects(desc->affinity, &cpu_online_map) )
+            {
+                cpumask_setall(desc->affinity);
+                affinity = &cpumask_all;
+            }
+            else if ( !cpumask_intersects(desc->arch.cpu_mask,
+                                          &cpu_online_map) )
+                affinity = desc->affinity;
+            if ( affinity )
+                desc->handler->set_affinity(desc, affinity);
+        }
 
         desc->status &= ~IRQ_DISABLED;
         desc->handler->startup(desc);