[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v10 03/32] ARM: vGIC: move irq_to_pending() calls under the VGIC VCPU lock



On Tue, 30 May 2017, Julien Grall wrote:
> Hi Andre,
> 
> On 26/05/17 18:35, Andre Przywara wrote:
> > So far irq_to_pending() is just a convenience function to lookup
> > statically allocated arrays. This will change with LPIs, which are
> > more dynamic, so the memory for their struct pending_irq might go away.
> > The proper answer to the issue of preventing stale pointers is
> > ref-counting, which requires more rework and will be introduced with
> > a later rework.
> > For now move the irq_to_pending() calls that are used with LPIs under the
> > VGIC VCPU lock, and only use the returned pointer while holding the lock.
> > This prevents the memory from being freed while we use it.
> > For the sake of completeness we take care about all irq_to_pending()
> > users, even those which later will never deal with LPIs.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
> > ---
> >  xen/arch/arm/gic.c  |  5 ++++-
> >  xen/arch/arm/vgic.c | 39 ++++++++++++++++++++++++++++++---------
> >  2 files changed, 34 insertions(+), 10 deletions(-)
> > 
> > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> > index da19130..dcb1783 100644
> > --- a/xen/arch/arm/gic.c
> > +++ b/xen/arch/arm/gic.c
> > @@ -402,10 +402,13 @@ static inline void gic_add_to_lr_pending(struct vcpu
> > *v, struct pending_irq *n)
> > 
> >  void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq)
> >  {
> > -    struct pending_irq *p = irq_to_pending(v, virtual_irq);
> > +    struct pending_irq *p;
> >      unsigned long flags;
> > 
> >      spin_lock_irqsave(&v->arch.vgic.lock, flags);
> > +
> > +    p = irq_to_pending(v, virtual_irq);
> > +
> >      if ( !list_empty(&p->lr_queue) )
> >          list_del_init(&p->lr_queue);
> >      spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
> > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> > index 54b2aad..69d732b 100644
> > --- a/xen/arch/arm/vgic.c
> > +++ b/xen/arch/arm/vgic.c
> > @@ -234,23 +234,29 @@ static int vgic_get_virq_priority(struct vcpu *v,
> > unsigned int virq)
> >  bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq)
> >  {
> >      unsigned long flags;
> > -    struct pending_irq *p = irq_to_pending(old, irq);
> > +    struct pending_irq *p;
> > +
> > +    spin_lock_irqsave(&old->arch.vgic.lock, flags);
> > +
> > +    p = irq_to_pending(old, irq);
> > 
> >      /* nothing to do for virtual interrupts */
> >      if ( p->desc == NULL )
> > +    {
> > +        spin_unlock_irqrestore(&old->arch.vgic.lock, flags);
> >          return true;
> > +    }
> > 
> >      /* migration already in progress, no need to do anything */
> >      if ( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
> >      {
> >          gprintk(XENLOG_WARNING, "irq %u migration failed: requested while
> > in progress\n", irq);
> > +        spin_unlock_irqrestore(&old->arch.vgic.lock, flags);
> >          return false;
> >      }
> > 
> >      perfc_incr(vgic_irq_migrates);
> > 
> > -    spin_lock_irqsave(&old->arch.vgic.lock, flags);
> > -
> >      if ( list_empty(&p->inflight) )
> >      {
> >          irq_set_affinity(p->desc, cpumask_of(new->processor));
> > @@ -285,6 +291,13 @@ void arch_move_irqs(struct vcpu *v)
> >      struct vcpu *v_target;
> >      int i;
> > 
> > +    /*
> > +     * We don't migrate LPIs at the moment.
> > +     * If we ever do, we must make sure that the struct pending_irq does
> > +     * not go away, as there is no lock preventing this here.
> > +     */
> > +    ASSERT(!is_lpi(vgic_num_irqs(d) - 1));
> 
> Hmmm? This raise a question of why vgic_num_irqs does not include the LPIs
> today...
> 
> > +
> >      for ( i = 32; i < vgic_num_irqs(d); i++ )
> >      {
> >          v_target = vgic_get_target_vcpu(v, i);
> > @@ -299,6 +312,7 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int
> > n)
> >  {
> >      const unsigned long mask = r;
> >      struct pending_irq *p;
> > +    struct irq_desc *desc;
> >      unsigned int irq;
> >      unsigned long flags;
> >      int i = 0;
> > @@ -307,14 +321,19 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int
> > n)
> >      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
> >          irq = i + (32 * n);
> >          v_target = vgic_get_target_vcpu(v, irq);
> > +
> > +        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
> >          p = irq_to_pending(v_target, irq);
> >          clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
> >          gic_remove_from_queues(v_target, irq);
> 
> gic_remove_from_queues is taking v_target vGIC lock. So you just introduced a
> deadlock. You remove it in the next patch but still, we should not introduce
> regression even temporarily. This would make to difficult to bisect the
> series.

Yeah, we cannot introduce regressions like this one.


> TBH, I am not a big fan of spreading the mess of vGIC locking when we are
> going to rework the vGIC and know that this code will not be called for LPIs.

I asked for this in
alpine.DEB.2.10.1705191729560.18759@sstabellini-ThinkPad-X260, this way
we covered all basis. The double lock is bad, but the rest of the
changes look OK to me.


> BTW, this series is not bisectable because the host ITS is only enabled from
> patch #12.
> 
> > -        if ( p->desc != NULL )
> > +        desc = p->desc;
> > +        spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> > +
> > +        if ( desc != NULL )
> >          {
> > -            spin_lock_irqsave(&p->desc->lock, flags);
> > -            p->desc->handler->disable(p->desc);
> > -            spin_unlock_irqrestore(&p->desc->lock, flags);
> > +            spin_lock_irqsave(&desc->lock, flags);
> > +            desc->handler->disable(desc);
> > +            spin_unlock_irqrestore(&desc->lock, flags);
> >          }
> >          i++;
> >      }
> > @@ -349,9 +368,9 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
> >      while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
> >          irq = i + (32 * n);
> >          v_target = vgic_get_target_vcpu(v, irq);
> > +        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
> >          p = irq_to_pending(v_target, irq);
> >          set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
> > -        spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
> >          if ( !list_empty(&p->inflight) && !test_bit(GIC_IRQ_GUEST_VISIBLE,
> > &p->status) )
> >              gic_raise_guest_irq(v_target, irq, p->priority);
> >          spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> > @@ -460,7 +479,7 @@ void vgic_clear_pending_irqs(struct vcpu *v)
> >  void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
> >  {
> >      uint8_t priority;
> > -    struct pending_irq *iter, *n = irq_to_pending(v, virq);
> > +    struct pending_irq *iter, *n;
> >      unsigned long flags;
> >      bool running;
> > 
> > @@ -468,6 +487,8 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int
> > virq)
> > 
> >      spin_lock_irqsave(&v->arch.vgic.lock, flags);
> > 
> > +    n = irq_to_pending(v, virq);
> > +
> >      /* vcpu offline */
> >      if ( test_bit(_VPF_down, &v->pause_flags) )
> >      {
> > 
> 
> Cheers,
> 
> -- 
> Julien Grall
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.