On 08/02/2021 09:41, Jürgen Groß wrote:
On 08.02.21 10:11, Julien Grall wrote:
Hi Juergen,

On 07/02/2021 12:58, Jürgen Groß wrote:
On 06.02.21 19:46, Julien Grall wrote:
Hi Juergen,

On 06/02/2021 10:49, Juergen Gross wrote:
The first three patches are fixes for XSA-332. The avoid WARN splats
and a performance issue with interdomain events.

Thanks for helping to figure out the problem. Unfortunately, I still see reliably the WARN splat with the latest Linux master (1e0d27fce010) + your first 3 patches.

I am using Xen 4.11 (1c7d984645f9) and dom0 is forced to use the 2L events ABI.

After some debugging, I think I have an idea what's went wrong. The problem happens when the event is initially bound from vCPU0 to a different vCPU.

 From the comment in xen_rebind_evtchn_to_cpu(), we are masking the event to prevent it being delivered on an unexpected vCPU. However, I believe the following can happen:

vCPU0                | vCPU1
                 |
                 | Call xen_rebind_evtchn_to_cpu()
receive event X            |
                 | mask event X
                 | bind to vCPU1
<vCPU descheduled>        | unmask event X
                 |
                 | receive event X
                 |
                 | handle_edge_irq(X)
handle_edge_irq(X)        |  -> handle_irq_event()
                 |   -> set IRQD_IN_PROGRESS
  -> set IRQS_PENDING        |
                 |   -> evtchn_interrupt()
                 |   -> clear IRQD_IN_PROGRESS
                 |  -> IRQS_PENDING is set
                 |  -> handle_irq_event()
                 |   -> evtchn_interrupt()
                 |     -> WARN()
                 |

All the lateeoi handlers expect a ONESHOT semantic and evtchn_interrupt() is doesn't tolerate any deviation.

I think the problem was introduced by 7f874a0447a9 ("xen/events: fix lateeoi irq acknowledgment") because the interrupt was disabled previously. Therefore we wouldn't do another iteration in handle_edge_irq().

I think you picked the wrong commit for blaming, as this is just
the last patch of the three patches you were testing.

I actually found the right commit for blaming but I copied the information from the wrong shell :/. The bug was introduced by:

c44b849cee8c ("xen/events: switch user event channels to lateeoi model")


Aside the handlers, I think it may impact the defer EOI mitigation because in theory if a 3rd vCPU is joining the party (let say vCPU A migrate the event from vCPU B to vCPU C). So info->{eoi_cpu, irq_epoch, eoi_time} could possibly get mangled?

For a fix, we may want to consider to hold evtchn_rwlock with the write permission. Although, I am not 100% sure this is going to prevent everything.

It will make things worse, as it would violate the locking hierarchy
(xen_rebind_evtchn_to_cpu() is called with the IRQ-desc lock held).

Ah, right.


On a first glance I think we'll need a 3rd masking state ("temporarily
masked") in the second patch in order to avoid a race with lateeoi.

In order to avoid the race you outlined above we need an "event is being
handled" indicator checked via test_and_set() semantics in
handle_irq_for_port() and reset only when calling clear_evtchn().

It feels like we are trying to workaround the IRQ flow we are using (i.e. handle_edge_irq()).

I'm not really sure this is the main problem here. According to your
analysis the main problem is occurring when handling the event, not when
handling the IRQ: the event is being received on two vcpus.

I don't think we can easily divide the two because we rely on the IRQ framework to handle the lifecycle of the event. So...


Our problem isn't due to the IRQ still being pending, but due it being
raised again, which should happen for a one shot IRQ the same way.

... I don't really see how the difference matter here. The idea is to re-use what's already existing rather than trying to re-invent the wheel with an extra lock (or whatever we can come up).

Cheers,

--
Julien Grall

Reply via email to