|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 04/10] ARM: vGIC: add struct pending_irq locking
On Fri, 5 May 2017, Andre Przywara wrote:
> Hi,
>
> On 04/05/17 17:21, Julien Grall wrote:
> > Hi Andre,
> >
> > On 04/05/17 16:31, Andre Przywara wrote:
> >> Introduce the proper locking sequence for the new pending_irq lock.
> >> This takes the lock around multiple accesses to struct members,
> >> also makes sure we observe the locking order (VGIC VCPU lock first,
> >> then pending_irq lock).
> >
> > This locking order should be explained in the code. Likely in vgic.h.
> >
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
> >> ---
> >> xen/arch/arm/gic.c | 26 ++++++++++++++++++++++++++
> >> xen/arch/arm/vgic.c | 12 +++++++++++-
> >> 2 files changed, 37 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >> index 67375a2..e175e9b 100644
> >> --- a/xen/arch/arm/gic.c
> >> +++ b/xen/arch/arm/gic.c
> >> @@ -351,6 +351,7 @@ void gic_disable_cpu(void)
> >> static inline void gic_set_lr(int lr, struct pending_irq *p,
> >> unsigned int state)
> >> {
> >> + ASSERT(spin_is_locked(&p->lock));
> >> ASSERT(!local_irq_is_enabled());
> >>
> >> gic_hw_ops->update_lr(lr, p, state);
> >> @@ -413,6 +414,7 @@ void gic_raise_guest_irq(struct vcpu *v, struct
> >> pending_irq *p)
> >> unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
> >>
> >> ASSERT(spin_is_locked(&v->arch.vgic.lock));
> >> + ASSERT(spin_is_locked(&p->lock));
> >>
> >> if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
> >> {
> >> @@ -439,6 +441,7 @@ static void gic_update_one_lr(struct vcpu *v, int i)
> >> gic_hw_ops->read_lr(i, &lr_val);
> >> irq = lr_val.virq;
> >> p = irq_to_pending(v, irq);
> >> + spin_lock(&p->lock);
> >> if ( lr_val.state & GICH_LR_ACTIVE )
> >> {
> >> set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
> >> @@ -495,6 +498,7 @@ static void gic_update_one_lr(struct vcpu *v, int i)
> >> }
> >> }
> >> }
> >> + spin_unlock(&p->lock);
> >> }
> >>
> >> void gic_clear_lrs(struct vcpu *v)
> >> @@ -545,14 +549,30 @@ static void gic_restore_pending_irqs(struct vcpu
> >> *v)
> >> /* No more free LRs: find a lower priority irq to evict */
> >> list_for_each_entry_reverse( p_r, inflight_r, inflight )
> >> {
> >> + if ( p_r->irq < p->irq )
> >> + {
> >> + spin_lock(&p_r->lock);
> >> + spin_lock(&p->lock);
> >> + }
> >> + else
> >> + {
> >> + spin_lock(&p->lock);
> >> + spin_lock(&p_r->lock);
> >> + }
> >
> > Please explain in the commit message and the code why this locking order.
> >
> >> if ( p_r->priority == p->priority )
> >> + {
> >> + spin_unlock(&p->lock);
> >> + spin_unlock(&p_r->lock);
> >> goto out;
> >> + }
> >> if ( test_bit(GIC_IRQ_GUEST_VISIBLE, &p_r->status) &&
> >> !test_bit(GIC_IRQ_GUEST_ACTIVE, &p_r->status) )
> >> goto found;
> >> }
> >> /* We didn't find a victim this time, and we won't next
> >> * time, so quit */
> >> + spin_unlock(&p->lock);
> >> + spin_unlock(&p_r->lock);
> >> goto out;
> >>
> >> found:
> >> @@ -562,12 +582,18 @@ found:
> >> clear_bit(GIC_IRQ_GUEST_VISIBLE, &p_r->status);
> >> gic_add_to_lr_pending(v, p_r);
> >> inflight_r = &p_r->inflight;
> >> +
> >> + spin_unlock(&p_r->lock);
> >> }
> >> + else
> >> + spin_lock(&p->lock);
> >>
> >> gic_set_lr(lr, p, GICH_LR_PENDING);
> >> list_del_init(&p->lr_queue);
> >> set_bit(lr, &this_cpu(lr_mask));
> >>
> >> + spin_unlock(&p->lock);
> >> +
> >> /* We can only evict nr_lrs entries */
> >> lrs--;
> >> if ( lrs == 0 )
> >> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> >> index f4ae454..44363bb 100644
> >> --- a/xen/arch/arm/vgic.c
> >> +++ b/xen/arch/arm/vgic.c
> >> @@ -356,11 +356,16 @@ 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);
> >> + spin_lock(&p->lock);
> >> +
> >> set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
> >> - spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
> >
> > IHMO, this should belong to a separate patch as not strictly relate to
> > this one.
>
> I don't think it makes much sense to split this, as this change is
> motivated by the introduction of the pending_irq lock, and we have to
> move the VGIC VCPU lock due to the locking order.
>
> >
> >> +
> >
> > Spurious change.
>
> Well, that helps to structure the code.
>
> >> if ( !list_empty(&p->inflight) &&
> >> !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
> >> gic_raise_guest_irq(v_target, p);
> >> + spin_unlock(&p->lock);
> >> spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> >> if ( p->desc != NULL )
> >> {
> >> @@ -482,10 +487,12 @@ void vgic_vcpu_inject_irq(struct vcpu *v,
> >> unsigned int virq)
> >> return;
> >> }
> >>
> >> + spin_lock(&n->lock);
> >> set_bit(GIC_IRQ_GUEST_QUEUED, &n->status);
> >>
> >> if ( !list_empty(&n->inflight) )
> >> {
> >> + spin_unlock(&n->lock);
> >> gic_raise_inflight_irq(v, n);
> >
> > Any reason to not code gic_raise_inflight_irq with the lock? This would
> > also simplify quite a lot the function and avoid unlock in pretty much
> > all the exit path.
>
> gic_raise_inflight_irq() calls gic_update_one_lr(), which works out the
> pending_irq from the LR number and then takes the lock.
> Yes, there are other ways of solving this:
> - remove gic_raise_inflight_irq() at all
> - rework gic_update_one_lr() to take a (locked) pending_irq already
>
> Both approaches have other issues that pop up, I think this solution
> here is the least hideous and least intrusive.
> Frankly I believe that removing gic_raise_inflight_irq() altogether is
> the best solution, but this requires more rework (which Stefano hinted
> at not liking too much) and I wanted to keep this series as simple as
> possible.
Just to be clear: I like any rework/refactoring you can come up with,
*after* ITS :-)
> >> goto out;
> >> }
> >> @@ -501,10 +508,13 @@ void vgic_vcpu_inject_irq(struct vcpu *v,
> >> unsigned int virq)
> >> if ( iter->priority > priority )
> >> {
> >> list_add_tail(&n->inflight, &iter->inflight);
> >> + spin_unlock(&n->lock);
> >> goto out;
> >> }
> >> }
> >> list_add_tail(&n->inflight, &v->arch.vgic.inflight_irqs);
> >> + spin_unlock(&n->lock);
> >> +
> >> out:
> >> spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
> >> /* we have a new higher priority irq, inject it into the guest */
> >>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |