diff mbox

[2/4] xen/x86: Drop erronious barriers

Message ID alpine.DEB.2.10.1612061152120.6598@sstabellini-ThinkPad-X260 (mailing list archive)
State New, archived
Headers show

Commit Message

Stefano Stabellini Dec. 6, 2016, 8:27 p.m. UTC
On Tue, 6 Dec 2016, Andrew Cooper wrote:
> On 05/12/2016 19:17, Stefano Stabellini wrote:
> > On Mon, 5 Dec 2016, Andrew Cooper wrote:
> >> None of these barriers serve any purpose, as they are not synchronising with
> >> any anything on remote CPUs.
> >>
> >> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> >> ---
> >> CC: Jan Beulich <JBeulich@suse.com>
> >> CC: Stefano Stabellini <sstabellini@kernel.org>
> >> CC: Julien Grall <julien.grall@arm.com>
> >>
> >> Restricting to just the $ARCH maintainers, as this is a project-wide sweep.
> >>
> >> Julien/Stefano: I think the ARM smpboot inhereted the erronious barrier usage
> >> from x86, but I don't know whether further development has gained a dependence
> >> on them.
> > We turned them into smp_wmb already (kudos to IanC).
> 
> Right, but the entire point I am trying to argue is that they are not
> needed in the first place.

This is the current code:

    CPU 1                                  CPU 0
    -----                                  -----

    init stuff                             read cpu_online_map

    write barrier                          

    write cpu_online_map                   do more initialization

    write barrier

    init more stuff


I agree that it's wrong, because the second write barrier in
start_secondary is useless and in addition we are missing a read barrier
in __cpu_up, corresponding to the first write barrier in
start_secondary.

I think it should look like:


    CPU 1                                  CPU 0
    -----                                  -----

    init stuff                             read cpu_online_map

    write barrier                          read barrier 

    write cpu_online_map                   do more initialization

    init more stuff


The patch is as follow.

Julien, what do you think?

Also, do we need to change the remaming smp_wmb() in start_secondary to
wmb() to ensure execution ordering as well as memory access ordering?

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>

Comments

Stefano Stabellini Dec. 6, 2016, 8:32 p.m. UTC | #1
On Tue, 6 Dec 2016, Stefano Stabellini wrote:
> On Tue, 6 Dec 2016, Andrew Cooper wrote:
> > On 05/12/2016 19:17, Stefano Stabellini wrote:
> > > On Mon, 5 Dec 2016, Andrew Cooper wrote:
> > >> None of these barriers serve any purpose, as they are not synchronising with
> > >> any anything on remote CPUs.
> > >>
> > >> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> > >> ---
> > >> CC: Jan Beulich <JBeulich@suse.com>
> > >> CC: Stefano Stabellini <sstabellini@kernel.org>
> > >> CC: Julien Grall <julien.grall@arm.com>
> > >>
> > >> Restricting to just the $ARCH maintainers, as this is a project-wide sweep.
> > >>
> > >> Julien/Stefano: I think the ARM smpboot inhereted the erronious barrier usage
> > >> from x86, but I don't know whether further development has gained a dependence
> > >> on them.
> > > We turned them into smp_wmb already (kudos to IanC).
> > 
> > Right, but the entire point I am trying to argue is that they are not
> > needed in the first place.

Just to be clear, on ARM the barriers are unneeded only if it is
unimportant that "init stuff" (which correspond to all the
initialization done in start_secondary up to smp_wmb) below is completed
before "write cpu_online_map". But it looks like we do want to complete
mmu, irq, timer initializations and set the current vcpu before marking
the cpu as online, right?


> This is the current code:
> 
>     CPU 1                                  CPU 0
>     -----                                  -----
> 
>     init stuff                             read cpu_online_map
> 
>     write barrier                          
> 
>     write cpu_online_map                   do more initialization
> 
>     write barrier
> 
>     init more stuff
> 
> 
> I agree that it's wrong, because the second write barrier in
> start_secondary is useless and in addition we are missing a read barrier
> in __cpu_up, corresponding to the first write barrier in
> start_secondary.
> 
> I think it should look like:
> 
> 
>     CPU 1                                  CPU 0
>     -----                                  -----
> 
>     init stuff                             read cpu_online_map
> 
>     write barrier                          read barrier 
> 
>     write cpu_online_map                   do more initialization
> 
>     init more stuff
> 
> 
> The patch is as follow.
> 
> Julien, what do you think?
> 
> Also, do we need to change the remaming smp_wmb() in start_secondary to
> wmb() to ensure execution ordering as well as memory access ordering?
> 
> Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
> 
> diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
> index 90ad1d0..c841a15 100644
> --- a/xen/arch/arm/smpboot.c
> +++ b/xen/arch/arm/smpboot.c
> @@ -311,7 +311,6 @@ void start_secondary(unsigned long boot_phys_offset,
>  
>      /* Now report this CPU is up */
>      cpumask_set_cpu(cpuid, &cpu_online_map);
> -    smp_wmb();
>  
>      local_irq_enable();
>      local_abort_enable();
> @@ -408,6 +407,7 @@ int __cpu_up(unsigned int cpu)
>          cpu_relax();
>          process_pending_softirqs();
>      }
> +    smp_rmb();
>  
>      /*
>       * Nuke start of day info before checking one last time if the CPU
>
Andrew Cooper Dec. 7, 2016, 1:03 a.m. UTC | #2
On 06/12/2016 20:32, Stefano Stabellini wrote:
> On Tue, 6 Dec 2016, Stefano Stabellini wrote:
>> On Tue, 6 Dec 2016, Andrew Cooper wrote:
>>> On 05/12/2016 19:17, Stefano Stabellini wrote:
>>>> On Mon, 5 Dec 2016, Andrew Cooper wrote:
>>>>> None of these barriers serve any purpose, as they are not synchronising with
>>>>> any anything on remote CPUs.
>>>>>
>>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>>>> ---
>>>>> CC: Jan Beulich <JBeulich@suse.com>
>>>>> CC: Stefano Stabellini <sstabellini@kernel.org>
>>>>> CC: Julien Grall <julien.grall@arm.com>
>>>>>
>>>>> Restricting to just the $ARCH maintainers, as this is a project-wide sweep.
>>>>>
>>>>> Julien/Stefano: I think the ARM smpboot inhereted the erronious barrier usage
>>>>> from x86, but I don't know whether further development has gained a dependence
>>>>> on them.
>>>> We turned them into smp_wmb already (kudos to IanC).
>>> Right, but the entire point I am trying to argue is that they are not
>>> needed in the first place.
> Just to be clear, on ARM the barriers are unneeded only if it is
> unimportant that "init stuff" (which correspond to all the
> initialization done in start_secondary up to smp_wmb) below is completed
> before "write cpu_online_map". But it looks like we do want to complete
> mmu, irq, timer initializations and set the current vcpu before marking
> the cpu as online, right?

No.  I am sorry, but this question suggests that you still don't appear
to understand barriers.

>
>
>> This is the current code:
>>
>>     CPU 1                                  CPU 0
>>     -----                                  -----
>>
>>     init stuff                             read cpu_online_map
>>
>>     write barrier                          
>>
>>     write cpu_online_map                   do more initialization
>>
>>     write barrier
>>
>>     init more stuff
>>
>>
>> I agree that it's wrong, because the second write barrier in
>> start_secondary is useless and in addition we are missing a read barrier
>> in __cpu_up, corresponding to the first write barrier in
>> start_secondary.
>>
>> I think it should look like:
>>
>>
>>     CPU 1                                  CPU 0
>>     -----                                  -----
>>
>>     init stuff                             read cpu_online_map
>>
>>     write barrier                          read barrier 
>>
>>     write cpu_online_map                   do more initialization
>>
>>     init more stuff

The barriers here serve no purpose, because you have missed an important
blocking while loop on CPU 0.

Recall, that the read/write barrier example is:

foo = a;
smp_rmb();
bar = b;

and

a = baz;
smp_wmb();
b = fromble;

This is specifically relevant *only* to the shared variables a and b,
where for correctness an update to a must be observed remotely before
the update to b.

If you do not have the explicitly same a and b on either side of the
smp_rmb/smp_wmb, then your code is wrong (and most likely, you shouldn't
be using the barriers).


The init sequence is a different scenario.

Processor 0 spins waiting to observe an update to cpu_online_map.

Processor 1 performs its init sequence, and mid way through, sets its
own bit in the cpu_online_map.  It then continues further init actions.

It does not matter whether processor 0 observes the update to
cpu_online_map slightly early or late compared to the local-state
updates from the other parts of processor 1's init sequence (because
processor 0 had better not be looking at the local-state changes).  Once
the bit is set in cpu_online_map, processor 1 is ready to be IPI'd to
give it work to do, etc.  Even if processor 0 hasn't observed all of the
local-state updates of processor 1, once it has seen the cpu_online_map
update, it knows that processor 1 is available to be IPI'd, and IPIing
processor 1 will cause execution with expected program order being
observed (from the point of view of processor 1).


The only consideration is whether processor 1 can make an action which
will prioritise the update to cpu_online_map becoming visible to the
rest of the system.  If there is such an action available, then an
argument can be made that making the update visible more quickly will
allow processor 0 to continue earlier.  However, such an action would be
entirely local to processor 1 and not related to anything happening on
processor 0.

I am not aware of any such action on x86, and my gut feeling is that no
other architecture would have one either.  The ability to fast forward
one specific update to the shared cache-coherency layer would only
complicate an already complicated area of silicon, and would only be
useful to micro-optimise a corner case; I can't see any system designers
considering it a useful feature to add.

~Andrew
Stefano Stabellini Dec. 7, 2016, 1:20 a.m. UTC | #3
On Wed, 7 Dec 2016, Andrew Cooper wrote:
> On 06/12/2016 20:32, Stefano Stabellini wrote:
> > On Tue, 6 Dec 2016, Stefano Stabellini wrote:
> >> On Tue, 6 Dec 2016, Andrew Cooper wrote:
> >>> On 05/12/2016 19:17, Stefano Stabellini wrote:
> >>>> On Mon, 5 Dec 2016, Andrew Cooper wrote:
> >>>>> None of these barriers serve any purpose, as they are not synchronising with
> >>>>> any anything on remote CPUs.
> >>>>>
> >>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> >>>>> ---
> >>>>> CC: Jan Beulich <JBeulich@suse.com>
> >>>>> CC: Stefano Stabellini <sstabellini@kernel.org>
> >>>>> CC: Julien Grall <julien.grall@arm.com>
> >>>>>
> >>>>> Restricting to just the $ARCH maintainers, as this is a project-wide sweep.
> >>>>>
> >>>>> Julien/Stefano: I think the ARM smpboot inhereted the erronious barrier usage
> >>>>> from x86, but I don't know whether further development has gained a dependence
> >>>>> on them.
> >>>> We turned them into smp_wmb already (kudos to IanC).
> >>> Right, but the entire point I am trying to argue is that they are not
> >>> needed in the first place.
> > Just to be clear, on ARM the barriers are unneeded only if it is
> > unimportant that "init stuff" (which correspond to all the
> > initialization done in start_secondary up to smp_wmb) below is completed
> > before "write cpu_online_map". But it looks like we do want to complete
> > mmu, irq, timer initializations and set the current vcpu before marking
> > the cpu as online, right?
> 
> No.  I am sorry, but this question suggests that you still don't appear
> to understand barriers.
> 
> >
> >
> >> This is the current code:
> >>
> >>     CPU 1                                  CPU 0
> >>     -----                                  -----
> >>
> >>     init stuff                             read cpu_online_map
> >>
> >>     write barrier                          
> >>
> >>     write cpu_online_map                   do more initialization
> >>
> >>     write barrier
> >>
> >>     init more stuff
> >>
> >>
> >> I agree that it's wrong, because the second write barrier in
> >> start_secondary is useless and in addition we are missing a read barrier
> >> in __cpu_up, corresponding to the first write barrier in
> >> start_secondary.
> >>
> >> I think it should look like:
> >>
> >>
> >>     CPU 1                                  CPU 0
> >>     -----                                  -----
> >>
> >>     init stuff                             read cpu_online_map
> >>
> >>     write barrier                          read barrier 
> >>
> >>     write cpu_online_map                   do more initialization
> >>
> >>     init more stuff
> 
> The barriers here serve no purpose, because you have missed an important
> blocking while loop on CPU 0.
> 
> Recall, that the read/write barrier example is:
> 
> foo = a;
> smp_rmb();
> bar = b;
> 
> and
> 
> a = baz;
> smp_wmb();
> b = fromble;
> 
> This is specifically relevant *only* to the shared variables a and b,
> where for correctness an update to a must be observed remotely before
> the update to b.
> 
> If you do not have the explicitly same a and b on either side of the
> smp_rmb/smp_wmb, then your code is wrong (and most likely, you shouldn't
> be using the barriers).
> 
> 
> The init sequence is a different scenario.
> 
> Processor 0 spins waiting to observe an update to cpu_online_map.
> 
> Processor 1 performs its init sequence, and mid way through, sets its
> own bit in the cpu_online_map.  It then continues further init actions.
> 
> It does not matter whether processor 0 observes the update to
> cpu_online_map slightly early or late compared to the local-state
> updates from the other parts of processor 1's init sequence (because
> processor 0 had better not be looking at the local-state changes).

In that case of course there is no need for barriers (I wrote something
similar in the other follow-up email). The case I was worried about is
exactly the one where processor 0 looks at one of the changes made by
processor 1.
Andrew Cooper Dec. 7, 2016, 1:46 a.m. UTC | #4
On 07/12/2016 01:20, Stefano Stabellini wrote:
> On Wed, 7 Dec 2016, Andrew Cooper wrote:
>> On 06/12/2016 20:32, Stefano Stabellini wrote:
>>> On Tue, 6 Dec 2016, Stefano Stabellini wrote:
>>>> On Tue, 6 Dec 2016, Andrew Cooper wrote:
>>>>> On 05/12/2016 19:17, Stefano Stabellini wrote:
>>>>>> On Mon, 5 Dec 2016, Andrew Cooper wrote:
>>>>>>> None of these barriers serve any purpose, as they are not synchronising with
>>>>>>> any anything on remote CPUs.
>>>>>>>
>>>>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>>>>>> ---
>>>>>>> CC: Jan Beulich <JBeulich@suse.com>
>>>>>>> CC: Stefano Stabellini <sstabellini@kernel.org>
>>>>>>> CC: Julien Grall <julien.grall@arm.com>
>>>>>>>
>>>>>>> Restricting to just the $ARCH maintainers, as this is a project-wide sweep.
>>>>>>>
>>>>>>> Julien/Stefano: I think the ARM smpboot inhereted the erronious barrier usage
>>>>>>> from x86, but I don't know whether further development has gained a dependence
>>>>>>> on them.
>>>>>> We turned them into smp_wmb already (kudos to IanC).
>>>>> Right, but the entire point I am trying to argue is that they are not
>>>>> needed in the first place.
>>> Just to be clear, on ARM the barriers are unneeded only if it is
>>> unimportant that "init stuff" (which correspond to all the
>>> initialization done in start_secondary up to smp_wmb) below is completed
>>> before "write cpu_online_map". But it looks like we do want to complete
>>> mmu, irq, timer initializations and set the current vcpu before marking
>>> the cpu as online, right?
>> No.  I am sorry, but this question suggests that you still don't appear
>> to understand barriers.
>>
>>>
>>>> This is the current code:
>>>>
>>>>     CPU 1                                  CPU 0
>>>>     -----                                  -----
>>>>
>>>>     init stuff                             read cpu_online_map
>>>>
>>>>     write barrier                          
>>>>
>>>>     write cpu_online_map                   do more initialization
>>>>
>>>>     write barrier
>>>>
>>>>     init more stuff
>>>>
>>>>
>>>> I agree that it's wrong, because the second write barrier in
>>>> start_secondary is useless and in addition we are missing a read barrier
>>>> in __cpu_up, corresponding to the first write barrier in
>>>> start_secondary.
>>>>
>>>> I think it should look like:
>>>>
>>>>
>>>>     CPU 1                                  CPU 0
>>>>     -----                                  -----
>>>>
>>>>     init stuff                             read cpu_online_map
>>>>
>>>>     write barrier                          read barrier 
>>>>
>>>>     write cpu_online_map                   do more initialization
>>>>
>>>>     init more stuff
>> The barriers here serve no purpose, because you have missed an important
>> blocking while loop on CPU 0.
>>
>> Recall, that the read/write barrier example is:
>>
>> foo = a;
>> smp_rmb();
>> bar = b;
>>
>> and
>>
>> a = baz;
>> smp_wmb();
>> b = fromble;
>>
>> This is specifically relevant *only* to the shared variables a and b,
>> where for correctness an update to a must be observed remotely before
>> the update to b.
>>
>> If you do not have the explicitly same a and b on either side of the
>> smp_rmb/smp_wmb, then your code is wrong (and most likely, you shouldn't
>> be using the barriers).
>>
>>
>> The init sequence is a different scenario.
>>
>> Processor 0 spins waiting to observe an update to cpu_online_map.
>>
>> Processor 1 performs its init sequence, and mid way through, sets its
>> own bit in the cpu_online_map.  It then continues further init actions.
>>
>> It does not matter whether processor 0 observes the update to
>> cpu_online_map slightly early or late compared to the local-state
>> updates from the other parts of processor 1's init sequence (because
>> processor 0 had better not be looking at the local-state changes).
> In that case of course there is no need for barriers (I wrote something
> similar in the other follow-up email). The case I was worried about is
> exactly the one where processor 0 looks at one of the changes made by
> processor 1.

Looking at an isolated change doesn't involve any ordering.

Ordering (and therefore barriers) are only relevant when looking at
exactly two related changes which need observing in a particular order. 
If you can reduce the BSP and AP boot sequence down to the two 3-line
examples above (with specifically identified variables/aggregates for a
and b on both sides), then you can make an argument for barriers being
necessary.

I should point out that I don't know whether the barriers are necessary
or unnecessary on ARM.  All I am trying to do is to ensure that everyone
has the same understanding of how barriers work before conclusions are
drawn (because they really are tricky).

~Andrew
Julien Grall Dec. 7, 2016, 6:31 p.m. UTC | #5
Hi Stefano,

On 06/12/2016 20:32, Stefano Stabellini wrote:
> On Tue, 6 Dec 2016, Stefano Stabellini wrote:
>> On Tue, 6 Dec 2016, Andrew Cooper wrote:
>>> On 05/12/2016 19:17, Stefano Stabellini wrote:
>>>> On Mon, 5 Dec 2016, Andrew Cooper wrote:
>>>>> None of these barriers serve any purpose, as they are not synchronising with
>>>>> any anything on remote CPUs.
>>>>>
>>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>>>> ---
>>>>> CC: Jan Beulich <JBeulich@suse.com>
>>>>> CC: Stefano Stabellini <sstabellini@kernel.org>
>>>>> CC: Julien Grall <julien.grall@arm.com>
>>>>>
>>>>> Restricting to just the $ARCH maintainers, as this is a project-wide sweep.
>>>>>
>>>>> Julien/Stefano: I think the ARM smpboot inhereted the erronious barrier usage
>>>>> from x86, but I don't know whether further development has gained a dependence
>>>>> on them.
>>>> We turned them into smp_wmb already (kudos to IanC).
>>>
>>> Right, but the entire point I am trying to argue is that they are not
>>> needed in the first place.
>
> Just to be clear, on ARM the barriers are unneeded only if it is
> unimportant that "init stuff" (which correspond to all the
> initialization done in start_secondary up to smp_wmb) below is completed
> before "write cpu_online_map". But it looks like we do want to complete
> mmu, irq, timer initializations and set the current vcpu before marking
> the cpu as online, right?

*mb are memory barriers. This would not prevent write to system 
registers and co-processor registers happening before "write 
cpu_online_map". Only an dsb(sy); isb() would ensure this.

However, I don't think we really care about the state of the hardware 
for a specific CPU. This should never be accessed by another one.

>
>> This is the current code:
>>
>>     CPU 1                                  CPU 0
>>     -----                                  -----
>>
>>     init stuff                             read cpu_online_map
>>
>>     write barrier
>>
>>     write cpu_online_map                   do more initialization
>>
>>     write barrier
>>
>>     init more stuff
>>
>>
>> I agree that it's wrong, because the second write barrier in
>> start_secondary is useless and in addition we are missing a read barrier
>> in __cpu_up, corresponding to the first write barrier in
>> start_secondary.
>>
>> I think it should look like:
>>
>>
>>     CPU 1                                  CPU 0
>>     -----                                  -----
>>
>>     init stuff                             read cpu_online_map
>>
>>     write barrier                          read barrier
>>
>>     write cpu_online_map                   do more initialization
>>
>>     init more stuff
>>
>>
>> The patch is as follow.
>>
>> Julien, what do you think?
>>
>> Also, do we need to change the remaming smp_wmb() in start_secondary to
>> wmb() to ensure execution ordering as well as memory access ordering?

I don't think so. If synchronization of hardware access was necessary it 
would have been taken care by the driver itself.

What we should care here is if there any xen internal state that are 
required between CPU0 and CPU1.

In this specific case, I think we should have the smp_wmb() barrier to 
ensure all write happening whilst calling local notifiers will be 
visible before the CPU mark itself as online. So IHMO, the patch looks 
good to me (see a small comment below).

>>
>> Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
>>
>> diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
>> index 90ad1d0..c841a15 100644
>> --- a/xen/arch/arm/smpboot.c
>> +++ b/xen/arch/arm/smpboot.c
>> @@ -311,7 +311,6 @@ void start_secondary(unsigned long boot_phys_offset,
>>
>>      /* Now report this CPU is up */
>>      cpumask_set_cpu(cpuid, &cpu_online_map);
>> -    smp_wmb();
>>
>>      local_irq_enable();
>>      local_abort_enable();
>> @@ -408,6 +407,7 @@ int __cpu_up(unsigned int cpu)
>>          cpu_relax();
>>          process_pending_softirqs();
>>      }
>> +    smp_rmb();

It would be good to start annotating the pair of barrier with "This 
barrier corresponds with the one in...". It would avoid "wild" barrier 
in the code :).

>>
>>      /*
>>       * Nuke start of day info before checking one last time if the CPU
>>

Regards,
Stefano Stabellini Dec. 7, 2016, 6:44 p.m. UTC | #6
On Wed, 7 Dec 2016, Julien Grall wrote:
> Hi Stefano,
> 
> On 06/12/2016 20:32, Stefano Stabellini wrote:
> > On Tue, 6 Dec 2016, Stefano Stabellini wrote:
> > > On Tue, 6 Dec 2016, Andrew Cooper wrote:
> > > > On 05/12/2016 19:17, Stefano Stabellini wrote:
> > > > > On Mon, 5 Dec 2016, Andrew Cooper wrote:
> > > > > > None of these barriers serve any purpose, as they are not
> > > > > > synchronising with
> > > > > > any anything on remote CPUs.
> > > > > > 
> > > > > > Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> > > > > > ---
> > > > > > CC: Jan Beulich <JBeulich@suse.com>
> > > > > > CC: Stefano Stabellini <sstabellini@kernel.org>
> > > > > > CC: Julien Grall <julien.grall@arm.com>
> > > > > > 
> > > > > > Restricting to just the $ARCH maintainers, as this is a project-wide
> > > > > > sweep.
> > > > > > 
> > > > > > Julien/Stefano: I think the ARM smpboot inhereted the erronious
> > > > > > barrier usage
> > > > > > from x86, but I don't know whether further development has gained a
> > > > > > dependence
> > > > > > on them.
> > > > > We turned them into smp_wmb already (kudos to IanC).
> > > > 
> > > > Right, but the entire point I am trying to argue is that they are not
> > > > needed in the first place.
> > 
> > Just to be clear, on ARM the barriers are unneeded only if it is
> > unimportant that "init stuff" (which correspond to all the
> > initialization done in start_secondary up to smp_wmb) below is completed
> > before "write cpu_online_map". But it looks like we do want to complete
> > mmu, irq, timer initializations and set the current vcpu before marking
> > the cpu as online, right?
> 
> *mb are memory barriers. This would not prevent write to system registers and
> co-processor registers happening before "write cpu_online_map". Only an
> dsb(sy); isb() would ensure this.
> 
> However, I don't think we really care about the state of the hardware for a
> specific CPU. This should never be accessed by another one.
> 
> > 
> > > This is the current code:
> > > 
> > >     CPU 1                                  CPU 0
> > >     -----                                  -----
> > > 
> > >     init stuff                             read cpu_online_map
> > > 
> > >     write barrier
> > > 
> > >     write cpu_online_map                   do more initialization
> > > 
> > >     write barrier
> > > 
> > >     init more stuff
> > > 
> > > 
> > > I agree that it's wrong, because the second write barrier in
> > > start_secondary is useless and in addition we are missing a read barrier
> > > in __cpu_up, corresponding to the first write barrier in
> > > start_secondary.
> > > 
> > > I think it should look like:
> > > 
> > > 
> > >     CPU 1                                  CPU 0
> > >     -----                                  -----
> > > 
> > >     init stuff                             read cpu_online_map
> > > 
> > >     write barrier                          read barrier
> > > 
> > >     write cpu_online_map                   do more initialization
> > > 
> > >     init more stuff
> > > 
> > > 
> > > The patch is as follow.
> > > 
> > > Julien, what do you think?
> > > 
> > > Also, do we need to change the remaming smp_wmb() in start_secondary to
> > > wmb() to ensure execution ordering as well as memory access ordering?
> 
> I don't think so. If synchronization of hardware access was necessary it would
> have been taken care by the driver itself.

I thought the same, thanks for confirming.


> What we should care here is if there any xen internal state that are required
> between CPU0 and CPU1.
> 
> In this specific case, I think we should have the smp_wmb() barrier to ensure
> all write happening whilst calling local notifiers will be visible before the
> CPU mark itself as online. So IHMO, the patch looks good to me (see a small
> comment below).

Andrew thinks that (on x86) there is actually nothing that CPU0 will be
looking at, that has been set by CPU1. However looking at the code it is
difficult to verify. There are many cpu notifiers and many things
written by start_secondary. I would prefer to submit this patch, and be
safe.


> > > 
> > > Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
> > > 
> > > diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
> > > index 90ad1d0..c841a15 100644
> > > --- a/xen/arch/arm/smpboot.c
> > > +++ b/xen/arch/arm/smpboot.c
> > > @@ -311,7 +311,6 @@ void start_secondary(unsigned long boot_phys_offset,
> > > 
> > >      /* Now report this CPU is up */
> > >      cpumask_set_cpu(cpuid, &cpu_online_map);
> > > -    smp_wmb();
> > > 
> > >      local_irq_enable();
> > >      local_abort_enable();
> > > @@ -408,6 +407,7 @@ int __cpu_up(unsigned int cpu)
> > >          cpu_relax();
> > >          process_pending_softirqs();
> > >      }
> > > +    smp_rmb();
> 
> It would be good to start annotating the pair of barrier with "This barrier
> corresponds with the one in...". It would avoid "wild" barrier in the code :).
> 
> > > 
> > >      /*
> > >       * Nuke start of day info before checking one last time if the CPU
> > > 
> 
> Regards,
> 
> -- 
> Julien Grall
>
Julien Grall Dec. 7, 2016, 6:55 p.m. UTC | #7
On 07/12/2016 18:44, Stefano Stabellini wrote:
> On Wed, 7 Dec 2016, Julien Grall wrote:
> Andrew thinks that (on x86) there is actually nothing that CPU0 will be
> looking at, that has been set by CPU1. However looking at the code it is
> difficult to verify. There are many cpu notifiers and many things
> written by start_secondary. I would prefer to submit this patch, and be
> safe.

I agree on this. Better be safe than hunting a bug later on.

Although, I think I just found an example for ARM. The gic_cpu_id (see 
gic-v2.c) is stored per-cpu and initialized by each CPU at boot.

gic_cpu_id is commonly used to send a SGI to a specific target. So we 
need to ensure that CPU0 will see this value before sending an SGI (see 
gicv2_send_SGI). Otherwise the SGI may go to the wild.

While you are sending a patch, can you document in the code why the 
barrier is present?

Cheers,
diff mbox

Patch

diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 90ad1d0..c841a15 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -311,7 +311,6 @@  void start_secondary(unsigned long boot_phys_offset,
 
     /* Now report this CPU is up */
     cpumask_set_cpu(cpuid, &cpu_online_map);
-    smp_wmb();
 
     local_irq_enable();
     local_abort_enable();
@@ -408,6 +407,7 @@  int __cpu_up(unsigned int cpu)
         cpu_relax();
         process_pending_softirqs();
     }
+    smp_rmb();
 
     /*
      * Nuke start of day info before checking one last time if the CPU