|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 3/3] xen/arm: vgic_migrate_irq: do not race against GIC_IRQ_GUEST_MIGRATING
On Fri, 3 Mar 2017, Julien Grall wrote:
> Hi Stefano,
>
> On 01/03/17 22:15, Stefano Stabellini wrote:
> > A potential race condition occurs when vgic_migrate_irq is called a
> > second time, while GIC_IRQ_GUEST_MIGRATING is already set. In that case,
> > vgic_migrate_irq takes a different vgic lock from gic_update_one_lr.
>
> Hmmm, vgic_migrate_irq will bail out before accessing inflight list if
> GIC_IRQ_GUEST_MIGRATING is already set:
>
> /* migrating already in progress, no need to do anything */
> if ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status )
> return;
>
> And test_bit is atomic. So I don't understand what is the corruption problem
> you mention.
The scenario is a bit convoluted: GIC_IRQ_GUEST_MIGRATING is already set
and vgic_migrate_irq is called to move the irq again, even though the
first migration is not complete yet. This could happen:
CPU 0 CPU 1
gic_update_one_lr
test_and_clear_bit MIGRATING
read target (old)
write target (new)
vgic_migrate_irq
test_bit MIGRATING
irq_set_affinity (new)
return
irq_set_affinity (old)
After this patch this would happen:
CPU 0 CPU 1
gic_update_one_lr
test_bit MIGRATING
read target (old)
write target (new)
vgic_migrate_irq
test MIGRATING &&
GIC_IRQ_GUEST_VISIBLE (false)
wait until !MIGRATING
irq_set_affinity (old)
clear_bit MIGRATING
irq_set_affinity (new)
> > vgic_migrate_irq running concurrently with gic_update_one_lr could cause
> > data corruptions, as they both access the inflight list.
> >
> > This patch fixes this problem. In vgic_migrate_irq after setting the new
> > vcpu target, it checks both GIC_IRQ_GUEST_MIGRATING and
> > GIC_IRQ_GUEST_VISIBLE. If they are both set we can just return because
> > we have already set the new target: when gic_update_one_lr reaches
> > the GIC_IRQ_GUEST_MIGRATING test, it will do the right thing.
> >
> > Otherwise, if GIC_IRQ_GUEST_MIGRATING is set but GIC_IRQ_GUEST_VISIBLE
> > is not, gic_update_one_lr is running at the very same time on another
> > pcpu, so it just waits until it completes (GIC_IRQ_GUEST_MIGRATING is
> > cleared).
> >
> > Signed-off-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
> > ---
> > xen/arch/arm/gic.c | 5 ++++-
> > xen/arch/arm/vgic.c | 16 ++++++++++++++--
> > 2 files changed, 18 insertions(+), 3 deletions(-)
> >
> > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> > index 16bb150..a805300 100644
> > --- a/xen/arch/arm/gic.c
> > +++ b/xen/arch/arm/gic.c
> > @@ -508,10 +508,13 @@ static void gic_update_one_lr(struct vcpu *v, int i)
> > * next pcpu, inflight is already cleared. No concurrent
> > * accesses to inflight. */
> > smp_mb();
> > - if ( test_and_clear_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
> > + if ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
> > {
> > struct vcpu *v_target = vgic_get_target_vcpu(v, irq);
> > irq_set_affinity(p->desc, cpumask_of(v_target->processor));
> > + /* Set the new affinity, then clear MIGRATING. */
> > + smp_mb();
> > + clear_bit(GIC_IRQ_GUEST_MIGRATING, &p->status);
> > }
> > }
> > }
> > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> > index a323e7e..9141b34 100644
> > --- a/xen/arch/arm/vgic.c
> > +++ b/xen/arch/arm/vgic.c
> > @@ -252,13 +252,25 @@ void vgic_migrate_irq(struct vcpu *old, struct vcpu
> > *new,
> > spin_lock_irqsave(&old->arch.vgic.lock, flags);
> > write_atomic(t_vcpu, new->vcpu_id);
> >
> > - /* migration already in progress, no need to do anything */
> > - if ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
> > + /* Set the new target, then check MIGRATING and VISIBLE, it pairs
> > + * with the barrier in gic_update_one_lr. */
> > + smp_mb();
> > +
> > + /* no need to do anything, gic_update_one_lr will take care of it */
> > + if ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) &&
> > + test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
> > {
> > spin_unlock_irqrestore(&old->arch.vgic.lock, flags);
> > return;
> > }
> >
> > + /* gic_update_one_lr is currently running, wait until its completion */
> > + while ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
> > + {
> > + cpu_relax();
> > + smp_rmb();
> > + }
> > +
> > if ( list_empty(&p->inflight) )
> > {
> > irq_set_affinity(p->desc, cpumask_of(new->processor));
> >
>
> Cheers,
>
> --
> Julien Grall
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |