|
[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
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.
Cheers,
Andre.
>> 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 */
>>
>
> Cheers,
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |