> Subject: Re: [PATCH 1/2] arm: irqchip: add lock in irqchip_inject_pending
> 
> On 05.12.19 03:28, Peng Fan wrote:
> > Hi Jan,
> >
> >> -----Original Message-----
> >> From: Jan Kiszka <[email protected]>
> >> Sent: 2019年12月3日 17:18
> >> To: Peng Fan <[email protected]>; [email protected]
> >> Cc: Alice Guo <[email protected]>
> >> Subject: Re: [PATCH 1/2] arm: irqchip: add lock in
> >> irqchip_inject_pending
> >>
> >> On 03.12.19 10:15, Peng Fan wrote:
> >>>> Subject: Re: [PATCH 1/2] arm: irqchip: add lock in
> >>>> irqchip_inject_pending
> >>>>
> >>>> On 03.12.19 09:58, Peng Fan wrote:
> >>>>>> Subject: Re: [PATCH 1/2] arm: irqchip: add lock in
> >>>>>> irqchip_inject_pending
> >>>>>>
> >>>>>> On 03.12.19 09:27, Peng Fan wrote:
> >>>>>>> Thinking about core0 is inject SGI to core1, core1 is handling
> >>>>>>> SGI interrupt.
> >>>>>>>
> >>>>>>> That means core0 might be in path to enqueue SGI into the
> >>>>>>> pending_irqs array, core1 might be in path handling SGI and pick
> >>>>>>> one from pending_irqs array. So need to use lock to protect
> >>>>>>> unqueue, not only enqueue.
> >>>>>>>
> >>>>>>> Signed-off-by: Peng Fan <[email protected]>
> >>>>>>> ---
> >>>>>>>
> >>>>>>> V1:
> >>>>>>>  The best case is only lock one entry, so no good solution,
> >>>>>>> because there is possibility that inject fail.
> >>>>>>>
> >>>>>>>  hypervisor/arch/arm-common/irqchip.c | 5 +++++
> >>>>>>>  1 file changed, 5 insertions(+)
> >>>>>>>
> >>>>>>> diff --git a/hypervisor/arch/arm-common/irqchip.c
> >>>>>>> b/hypervisor/arch/arm-common/irqchip.c
> >>>>>>> index 1c881b64..fbaa3099 100644
> >>>>>>> --- a/hypervisor/arch/arm-common/irqchip.c
> >>>>>>> +++ b/hypervisor/arch/arm-common/irqchip.c
> >>>>>>> @@ -279,11 +279,14 @@ void irqchip_inject_pending(void)
> >>>>>>>       struct pending_irqs *pending =
> &this_cpu_public()->pending_irqs;
> >>>>>>>       u16 irq_id, sender;
> >>>>>>>
> >>>>>>> +     spin_lock(&pending->lock);
> >>>>>>> +
> >>>>>>>       while (pending->head != pending->tail) {
> >>>>>>>               irq_id = pending->irqs[pending->head];
> >>>>>>>               sender = pending->sender[pending->head];
> >>>>>>>
> >>>>>>>               if (irqchip.inject_irq(irq_id, sender) == -EBUSY) {
> >>>>>>> +                     spin_unlock(&pending->lock);
> >>>>>>>                       /*
> >>>>>>>                        * The list registers are full, trigger 
> >>>>>>> maintenance
> >>>>>>>                        * interrupt and leave.
> >>>>>>> @@ -295,6 +298,8 @@ void irqchip_inject_pending(void)
> >>>>>>>               pending->head = (pending->head + 1) %
> MAX_PENDING_IRQS;
> >>>>>>>       }
> >>>>>>>
> >>>>>>> +     spin_unlock(&pending->lock);
> >>>>>>> +
> >>>>>>>       /*
> >>>>>>>        * The software interrupt queue is empty - turn off the
> >>>> maintenance
> >>>>>>>        * interrupt.
> >>>>>>>
> >>>>>>
> >>>>>> Did you see real corruptions?
> >>>>>
> >>>>> No. just code inspection currently. We met some SGI inject return
> >>>>> -EBUSY, so go through the code, and think this piece code needs a lock.
> >>>>>
> >>>>>>
> >>>>>> The idea behind this was that the injection to the lock-less
> >>>>>> queue happens in a way that it won't make changes visible to the
> >>>>>> consumer that are inconsistent, hence the barrier in
> irqchip_set_pending.
> >>>>>> Looking that again, though, we possibly need another barrier,
> >>>>>> right before updating
> >>>>>> pending->tail.
> >>>>>
> >>>>> Barrier could not prohibit enqueue/unqueue contention.
> >>>>> enqueue will check head, unqueue will update head.
> >>>>
> >>>> Some topic as with lockless enqueuing: We need a barrier to shield
> >>>> the readout of the head entry from the update of pending->head. So,
> >>>> we are definitely lacking barriers here, but I don't think we need
> >>>> the spinlock between producer and consumer because there is only
> >>>> one
> >> consumer.
> >>>
> >>> Lock-free should be possible, let me work out a non-lock solution.
> >>
> >> This is what comes to my mind so far, but please re-check carefully:
> >>
> >> diff --git a/hypervisor/arch/arm-common/irqchip.c
> >> b/hypervisor/arch/arm-common/irqchip.c
> >> index 1c881b64..a83cd81d 100644
> >> --- a/hypervisor/arch/arm-common/irqchip.c
> >> +++ b/hypervisor/arch/arm-common/irqchip.c
> >> @@ -246,12 +246,12 @@ void irqchip_set_pending(struct public_per_cpu
> >> *cpu_public, u16 irq_id)
> >>    if (new_tail != pending->head) {
> >>            pending->irqs[pending->tail] = irq_id;
> >>            pending->sender[pending->tail] = sender;
> >> -          pending->tail = new_tail;
> >>            /*
> >> -           * Make the change to pending_irqs.tail visible before the
> >> -           * caller sends SGI_INJECT.
> >> +           * Make the entry content visible before updating the tail
> >> +           * index.
> >>             */
> >>            memory_barrier();
> >> +          pending->tail = new_tail;
> >
> > The spin_unlock implies memory barrier. I think no need memory_barrier
> here.
> 
> We /might/ be fine here for the archs we support, but Linux is more
> strict:
> 
> "(2) RELEASE operation implication:
> 
>      Memory operations issued before the RELEASE will be completed
> before the
>      RELEASE operation has completed.
> 
>      Memory operations issued after the RELEASE may be completed before
> the
>      RELEASE operation has completed."
> 
> Now, the x86 is ordered anyway, ARMv7 indeed has the same barrier in the
> unload as in the memory_barrier(). However, ARM64 is not that clear to me.

ARM64 STLRH:
Store-Release Register Halfword stores a halfword from a 32-bit register to a
 memory location. The instruction also has memory ordering semantics as 
described in Load-Acquire, Load-AcquirePC, and Store-Release on page B2-108.

DDI0487D version, B2-108:
The Load-Acquire, Load-AcquirePC, and Store-Release instructions can remove
the requirement to use the explicit DMB instruction.

Hope this is clear.

Thanks,
Peng.

> 
> Jan
> 
> >>    }
> >>
> >>    spin_unlock(&pending->lock);
> >> @@ -264,6 +264,12 @@ void irqchip_set_pending(struct public_per_cpu
> >> *cpu_public, u16 irq_id)
> >>    if (local_injection) {
> >>            irqchip.enable_maint_irq(true);
> >>    } else {
> >> +          /*
> >> +           * Make the change to pending_irqs.tail visible before the
> >> +           * caller sends SGI_INJECT.
> >> +           */
> >> +          memory_barrier();
> >
> > Not needed, see above, spin_unlock already done this.
> >
> >> +
> >>            sgi.targets = irqchip_get_cpu_target(cpu_public->cpu_id);
> >>            sgi.cluster_id =
> >>                    irqchip_get_cluster_target(cpu_public->cpu_id);
> >> @@ -292,6 +298,12 @@ void irqchip_inject_pending(void)
> >>                    return;
> >>            }
> >>
> >> +          /*
> >> +           * Ensure that the entry was read befor updating the head
> >> +           * index.
> >> +           */
> >> +          memory_barrier();
> > No need. The index update will not be speculative before reading
> pending->head.
> >> +
> >>            pending->head = (pending->head + 1) % MAX_PENDING_IRQS;
> >
> > Need a barrier here, to make update visible to producer.
> >
> >>    }
> >
> > My version,
> >
> > diff --git a/hypervisor/arch/arm-common/irqchip.c
> > b/hypervisor/arch/arm-common/irqchip.c
> > index 1c881b64..5abf1c37 100644
> > --- a/hypervisor/arch/arm-common/irqchip.c
> > +++ b/hypervisor/arch/arm-common/irqchip.c
> > @@ -247,13 +247,12 @@ void irqchip_set_pending(struct public_per_cpu
> *cpu_public, u16 irq_id)
> >                 pending->irqs[pending->tail] = irq_id;
> >                 pending->sender[pending->tail] = sender;
> >                 pending->tail = new_tail;
> > -               /*
> > -                * Make the change to pending_irqs.tail visible before
> the
> > -                * caller sends SGI_INJECT.
> > -                */
> > -               memory_barrier();
> >         }
> >
> > +       /*
> > +        * spin_unlock will make the change to pending_irqs.tail and
> > +        * entry content visible before the caller sends SGI_INJECT.
> > +        */
> >         spin_unlock(&pending->lock);
> >
> >         /*
> > @@ -293,6 +292,9 @@ void irqchip_inject_pending(void)
> >                 }
> >
> >                 pending->head = (pending->head + 1) %
> > MAX_PENDING_IRQS;
> > +
> > +               /* Make the change to pending->head visible to
> enqueue. */
> > +               memory_barrier();
> >         }
> >
> >         /*
> >
> > Thanks,
> > Peng.
> >>
> >>
> >> Thanks for bringing this up!
> >>
> >> Jan
> >>
> >> --
> >> Siemens AG, Corporate Technology, CT RDA IOT SES-DE Corporate
> >> Competence Center Embedded Linux
> 
> 
> --
> Siemens AG, Corporate Technology, CT RDA IOT SES-DE Corporate
> Competence Center Embedded Linux
> 
> --
> You received this message because you are subscribed to the Google Groups
> "Jailhouse" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgroups
> .google.com%2Fd%2Fmsgid%2Fjailhouse-dev%2Fbef9b0b0-3bc0-4982-3b3d-
> aa829ad6ceb5%2540siemens.com&amp;data=02%7C01%7Cpeng.fan%40nxp
> .com%7C10ff76f9bdad430d02d208d77959a6aa%7C686ea1d3bc2b4c6fa92cd
> 99c5c301635%7C0%7C0%7C637111298262016631&amp;sdata=z9GG03UgG
> tQUqoaRzSrZip%2BA0pM7mxUM5YrAJmJ6QPI%3D&amp;reserved=0.

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/DB7PR04MB44907526C0E8FAB7CEECA8B9885C0%40DB7PR04MB4490.eurprd04.prod.outlook.com.

Reply via email to