All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] futex:  replace bare barrier() with a READ_ONCE()
@ 2016-02-29 11:41 Jianyu Zhan
  2016-02-29 22:22 ` Darren Hart
  0 siblings, 1 reply; 7+ messages in thread
From: Jianyu Zhan @ 2016-02-29 11:41 UTC (permalink / raw)
  To: linux-kernel; +Cc: tglx, dave, peterz, akpm, mingo, dvhart, bigeasy, nasa4836

Commit e91467ecd1ef ("bug in futex unqueue_me") introduces a barrier()
in unqueue_me(), to address a pointer aliasing problem in s390x, between
q->lock_ptr and local variable lock_ptr.

Since there is a retry logic to reload q->lock_ptr into local variable lock_ptr,
s390x generates code that aliases q->lock_ptr with lock_ptr, while q->lock_ptr
might change between retries, which beats the alias and causes problem.

This patch replaces this bare barrier() with a READ_ONCE(), a weaker form of
barrier(), which could be more informative.

And furthermore, this retry logic is effectively the same with:

	while (lock_ptr = q->lock_ptr)
		do_something_with(lock_ptr);

and compiler is at its will to merge successive load of q->lock_ptr, which is also problematic
at this scenario. READ_ONCE() can avoid this problem.

Signed-off-by: Jianyu Zhan <nasa4836@gmail.com>
---
 kernel/futex.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/kernel/futex.c b/kernel/futex.c
index 5d6ce64..20e8466 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1927,8 +1927,12 @@ static int unqueue_me(struct futex_q *q)
 
 	/* In the common case we don't take the spinlock, which is nice. */
 retry:
-	lock_ptr = q->lock_ptr;
-	barrier();
+	/*
+	 *  q->lock_ptr can change and a pointer aliasing(of lock_ptr) will cause problem, 
+	 *  and also to avoid potential compiler merging of successive load of q->lock_ptr under
+	 *  this retry logic, so we use READ_ONCE() here.
+	 */
+	lock_ptr = READ_ONCE(q->lock_ptr);
 	if (lock_ptr != NULL) {
 		spin_lock(lock_ptr);
 		/*
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] futex:  replace bare barrier() with a READ_ONCE()
  2016-02-29 11:41 [PATCH] futex: replace bare barrier() with a READ_ONCE() Jianyu Zhan
@ 2016-02-29 22:22 ` Darren Hart
  2016-03-01  0:44   ` Jianyu Zhan
  0 siblings, 1 reply; 7+ messages in thread
From: Darren Hart @ 2016-02-29 22:22 UTC (permalink / raw)
  To: Jianyu Zhan
  Cc: linux-kernel, tglx, dave, peterz, akpm, mingo, dvhart, bigeasy

On Mon, Feb 29, 2016 at 07:41:33PM +0800, Jianyu Zhan wrote:
> Commit e91467ecd1ef ("bug in futex unqueue_me") introduces a barrier()
> in unqueue_me(), to address a pointer aliasing problem in s390x, between
> q->lock_ptr and local variable lock_ptr.
> 
> Since there is a retry logic to reload q->lock_ptr into local variable lock_ptr,
> s390x generates code that aliases q->lock_ptr with lock_ptr, while q->lock_ptr
> might change between retries, which beats the alias and causes problem.

You've mention it causes problems a few times, but you do not specify what
problem it causes or how it manifests.

Is this a theoretical bug, or have you experienced a failure case. If so, how
did this manifest? Do you have a reproducer we could add to the futex testsuite
in the kernel selftests?

> 
> This patch replaces this bare barrier() with a READ_ONCE(), a weaker form of
> barrier(), which could be more informative.
> 
> And furthermore, this retry logic is effectively the same with:
> 
> 	while (lock_ptr = q->lock_ptr)
> 		do_something_with(lock_ptr);
> 
> and compiler is at its will to merge successive load of q->lock_ptr, which is also problematic
> at this scenario. READ_ONCE() can avoid this problem.
> 
> Signed-off-by: Jianyu Zhan <nasa4836@gmail.com>
> ---
>  kernel/futex.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/futex.c b/kernel/futex.c
> index 5d6ce64..20e8466 100644
> --- a/kernel/futex.c
> +++ b/kernel/futex.c
> @@ -1927,8 +1927,12 @@ static int unqueue_me(struct futex_q *q)
>  
>  	/* In the common case we don't take the spinlock, which is nice. */
>  retry:
> -	lock_ptr = q->lock_ptr;
> -	barrier();
> +	/*
> +	 *  q->lock_ptr can change and a pointer aliasing(of lock_ptr) will cause problem, 
> +	 *  and also to avoid potential compiler merging of successive load of q->lock_ptr under
> +	 *  this retry logic, so we use READ_ONCE() here.
> +	 */
> +	lock_ptr = READ_ONCE(q->lock_ptr);
>  	if (lock_ptr != NULL) {
>  		spin_lock(lock_ptr);
>  		/*
> -- 
> 2.4.3
> 
> 

-- 
Darren Hart
Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] futex: replace bare barrier() with a READ_ONCE()
  2016-02-29 22:22 ` Darren Hart
@ 2016-03-01  0:44   ` Jianyu Zhan
  2016-03-02  1:37     ` Darren Hart
  0 siblings, 1 reply; 7+ messages in thread
From: Jianyu Zhan @ 2016-03-01  0:44 UTC (permalink / raw)
  To: Darren Hart
  Cc: LKML, Thomas Gleixner, dave, Peter Zijlstra, Andrew Morton,
	Ingo Molnar, dvhart, bigeasy, Paul McKenney

On Tue, Mar 1, 2016 at 6:22 AM, Darren Hart <dvhart@infradead.org> wrote:
> You've mention it causes problems a few times, but you do not specify what
> problem it causes or how it manifests.
>
> Is this a theoretical bug, or have you experienced a failure case. If so, how
> did this manifest? Do you have a reproducer we could add to the futex testsuite
> in the kernel selftests?


1.  For the first problem I memtioned, it is a bug that described in
commit e91467ecd1ef.

The scenario is like:

     lock_ptr = q->lock_ptr
     if (lock_ptr != 0)  spin_lock(lock_ptr)

and the compiler generates code that is equivalent to :

     if (q->lock_ptr != 0) spin_lock(q->lock_ptr)

The problem is q->lock_ptr can change between  the test of nullness of
q->lock_ptr and the lock on q->lock_ptr
So a barrier() is inserted into the load of q->lock_ptr and the test
of nullness,  to avoid the pointer aliasing.

Apparently,   a READ_ONCE() fits the goal here.


2.  For the second problem I memtioned,  yes, it is theoretical,  and
it is also due to  q->lock_ptr can change between
the test of nullness of q->lock_ptr and the lock on q->lock_ptr.

the code is

retry:
       lock_ptr = q->lock_ptr;
       if (lock_ptr != 0)  {
                  spin_lock(lock_ptr)
                  if (unlikely(lock_ptr != q->lock_ptr)) {
                        spin_unlock(lock_ptr);
                         goto retry;
                  }
                   ...
       }

which is effectively the same as :

 while (lock_ptr = q->lock_ptr) {
                  spin_lock(lock_ptr)
                  if (unlikely(lock_ptr != q->lock_ptr)) {
                        spin_unlock(lock_ptr);
                         goto retry;
                  }
                   ...
}

This might cause the compiler load the q->lock_ptr once and use it
many times,  quoted from
memory-barriers.txt:


 (*) The compiler is within its rights to reload a variable, for example,
    in cases where high register pressure prevents the compiler from
    keeping all data of interest in registers.  The compiler might
    therefore optimize the variable 'tmp' out of our previous example:

       while (tmp = a)
               do_something_with(tmp);

    This could result in the following code, which is perfectly safe in
    single-threaded code, but can be fatal in concurrent code:

       while (a)
               do_something_with(a);

    For example, the optimized version of this code could result in
    passing a zero to do_something_with() in the case where the variable
    a was modified by some other CPU between the "while" statement and
    the call to do_something_with().

    Again, use READ_ONCE() to prevent the compiler from doing this:

       while (tmp = READ_ONCE(a))
               do_something_with(tmp);




So,  due to these two reason,  I propose this patch.


Thanks,
Jianyu Zhan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] futex: replace bare barrier() with a READ_ONCE()
  2016-03-01  0:44   ` Jianyu Zhan
@ 2016-03-02  1:37     ` Darren Hart
  2016-03-02  2:31       ` Jianyu Zhan
  0 siblings, 1 reply; 7+ messages in thread
From: Darren Hart @ 2016-03-02  1:37 UTC (permalink / raw)
  To: Jianyu Zhan
  Cc: LKML, Thomas Gleixner, dave, Peter Zijlstra, Andrew Morton,
	Ingo Molnar, dvhart, bigeasy, Paul McKenney

On Tue, Mar 01, 2016 at 08:44:48AM +0800, Jianyu Zhan wrote:
> On Tue, Mar 1, 2016 at 6:22 AM, Darren Hart <dvhart@infradead.org> wrote:
> > You've mention it causes problems a few times, but you do not specify what
> > problem it causes or how it manifests.
> >
> > Is this a theoretical bug, or have you experienced a failure case. If so, how
> > did this manifest? Do you have a reproducer we could add to the futex testsuite
> > in the kernel selftests?
> 
> 
> 1.  For the first problem I memtioned, it is a bug that described in
> commit e91467ecd1ef.
> 
> The scenario is like:
> 
>      lock_ptr = q->lock_ptr
>      if (lock_ptr != 0)  spin_lock(lock_ptr)
> 
> and the compiler generates code that is equivalent to :
> 
>      if (q->lock_ptr != 0) spin_lock(q->lock_ptr)
> 
> The problem is q->lock_ptr can change between  the test of nullness of
> q->lock_ptr and the lock on q->lock_ptr
> So a barrier() is inserted into the load of q->lock_ptr and the test
> of nullness,  to avoid the pointer aliasing.
> 
> Apparently,   a READ_ONCE() fits the goal here.


read_once will use a *volatile assignment instead of calling barrier()
directly for a word size argument.

With weak statements like "apparently" (above) and "could be" (from the original
post: This patch replaces this bare barrier() with a READ_ONCE(), a weaker form
of barrier(), which could be more informative.)" I do not see a compelling
reason to change what is notoriously fragile code with respect to barriers.

As for #2...

> 2.  For the second problem I memtioned,  yes, it is theoretical,  and
> it is also due to  q->lock_ptr can change between
> the test of nullness of q->lock_ptr and the lock on q->lock_ptr.
> 
> the code is
> 
> retry:
>        lock_ptr = q->lock_ptr;
>        if (lock_ptr != 0)  {
>                   spin_lock(lock_ptr)
>                   if (unlikely(lock_ptr != q->lock_ptr)) {
>                         spin_unlock(lock_ptr);
>                          goto retry;
>                   }
>                    ...
>        }
> 
> which is effectively the same as :
> 
>  while (lock_ptr = q->lock_ptr) {
>                   spin_lock(lock_ptr)
>                   if (unlikely(lock_ptr != q->lock_ptr)) {
>                         spin_unlock(lock_ptr);
>                          goto retry;
>                   }
>                    ...
> }
> 
> This might cause the compiler load the q->lock_ptr once and use it
> many times,  quoted from
> memory-barriers.txt:
> 
> 
>  (*) The compiler is within its rights to reload a variable, for example,
>     in cases where high register pressure prevents the compiler from
>     keeping all data of interest in registers.  The compiler might
>     therefore optimize the variable 'tmp' out of our previous example:
> 
>        while (tmp = a)
>                do_something_with(tmp);
> 
>     This could result in the following code, which is perfectly safe in
>     single-threaded code, but can be fatal in concurrent code:
> 
>        while (a)
>                do_something_with(a);
> 
>     For example, the optimized version of this code could result in
>     passing a zero to do_something_with() in the case where the variable
>     a was modified by some other CPU between the "while" statement and
>     the call to do_something_with().
> 
>     Again, use READ_ONCE() to prevent the compiler from doing this:
> 
>        while (tmp = READ_ONCE(a))
>                do_something_with(tmp);
> 

OK, so this is really the meat of the argument for the patch. You are looking to
add a compiler barrier instead of a CPU memory barrier. This should be what your
commit message is focused on and it should provide compelling evidence to
justify risking the change.

Compelling evidence for a compiler barrier would be a disassembly of the code
block before and after, demonstrating the compiler generating broken code and the
compiler generating correct code.

In addition to this, however, I would want to see a strong convincing argument
that the READ_ONCE volatile cast is sufficient to cover the original case which
motivated the addition of the barrier() (not "apparently" and "could be").

Thanks,

-- 
Darren Hart
Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] futex: replace bare barrier() with a READ_ONCE()
  2016-03-02  1:37     ` Darren Hart
@ 2016-03-02  2:31       ` Jianyu Zhan
  2016-03-02  6:39         ` Darren Hart
  0 siblings, 1 reply; 7+ messages in thread
From: Jianyu Zhan @ 2016-03-02  2:31 UTC (permalink / raw)
  To: Darren Hart
  Cc: LKML, Thomas Gleixner, dave, Peter Zijlstra, Andrew Morton,
	Ingo Molnar, dvhart, bigeasy, Paul McKenney

On Wed, Mar 2, 2016 at 9:37 AM, Darren Hart <dvhart@infradead.org> wrote:
> read_once will use a *volatile assignment instead of calling barrier()
> directly for a word size argument.
>
> With weak statements like "apparently" (above) and "could be" (from the original
> post: This patch replaces this bare barrier() with a READ_ONCE(), a weaker form
> of barrier(), which could be more informative.)" I do not see a compelling
> reason to change what is notoriously fragile code with respect to barriers.
>


Fair enough.  The "apparently" wording is lame without assembly code evidence.
I do not have such a s390 machine, so I have cc''ed the original
author incorporating this barrier(),
hopefully he could help test  this.

By "could be more informative"  I mean a READ_ONCE has explanatory
effect by its name, instead of
a bare barrier() without more inline comment for why.

As I said the retry code logic is effectively the same as

while (lock_ptr = READ_ONCE(q->lock_ptr)) {
                   spin_lock(lock_ptr)
                   if (unlikely(lock_ptr != q->lock_ptr)) {
                         spin_unlock(lock_ptr);
                   }

                   ...
}

in which case READ_ONCE could perfectly fit, in that it will make
compiler only read it once in every testing condition,
which will eliminate the original problem that commit e91467ecd1ef
addressed, though assembly code proof is needed.

Actually, the quotation I argued in previous mail could be used again
here, from memory-barriers.txt:

 (*) The compiler is within its rights to merge successive loads from
     the same variable.  Such merging can cause the compiler to "optimize"
     the following code:

        while (tmp = a)
                do_something_with(tmp);

     into the following code, which, although in some sense legitimate
     for single-threaded code, is almost certainly not what the developer
     intended:

        if (tmp = a)
                for (;;)
                        do_something_with(tmp);

     Use READ_ONCE() to prevent the compiler from doing this to you:

        while (tmp = READ_ONCE(a))
                do_something_with(tmp);


I might be wrong, so I have cc'ed Paul, and Peter,  I wish they give comment :-)


> As for #2...
>
>> 2.  For the second problem I memtioned,  yes, it is theoretical,  and
>> it is also due to  q->lock_ptr can change between
>> the test of nullness of q->lock_ptr and the lock on q->lock_ptr.
>>
>> the code is
>>
>> retry:
>>        lock_ptr = q->lock_ptr;
>>        if (lock_ptr != 0)  {
>>                   spin_lock(lock_ptr)
>>                   if (unlikely(lock_ptr != q->lock_ptr)) {
>>                         spin_unlock(lock_ptr);
>>                          goto retry;
>>                   }
>>                    ...
>>        }
>>
>> which is effectively the same as :
>>
>>  while (lock_ptr = q->lock_ptr) {
>>                   spin_lock(lock_ptr)
>>                   if (unlikely(lock_ptr != q->lock_ptr)) {
>>                         spin_unlock(lock_ptr);
>>                          goto retry;
>>                   }
>>                    ...
>> }
>>
>> This might cause the compiler load the q->lock_ptr once and use it
>> many times,  quoted from
>> memory-barriers.txt:
>>
>>
>>  (*) The compiler is within its rights to reload a variable, for example,
>>     in cases where high register pressure prevents the compiler from
>>     keeping all data of interest in registers.  The compiler might
>>     therefore optimize the variable 'tmp' out of our previous example:
>>
>>        while (tmp = a)
>>                do_something_with(tmp);
>>
>>     This could result in the following code, which is perfectly safe in
>>     single-threaded code, but can be fatal in concurrent code:
>>
>>        while (a)
>>                do_something_with(a);
>>
>>     For example, the optimized version of this code could result in
>>     passing a zero to do_something_with() in the case where the variable
>>     a was modified by some other CPU between the "while" statement and
>>     the call to do_something_with().
>>
>>     Again, use READ_ONCE() to prevent the compiler from doing this:
>>
>>        while (tmp = READ_ONCE(a))
>>                do_something_with(tmp);
>>
>
> OK, so this is really the meat of the argument for the patch. You are looking to
> add a compiler barrier instead of a CPU memory barrier. This should be what your
> commit message is focused on and it should provide compelling evidence to
> justify risking the change.
>
> Compelling evidence for a compiler barrier would be a disassembly of the code
> block before and after, demonstrating the compiler generating broken code and the
> compiler generating correct code.
>
> In addition to this, however, I would want to see a strong convincing argument
> that the READ_ONCE volatile cast is sufficient to cover the original case which
> motivated the addition of the barrier() (not "apparently" and "could be").

As for #2, this is pure theoretical induction from this quotation, I
do have no convincing argument
and again I would like Paul to help clarify this.


Thanks very much!


Regards,
Jianyu Zhan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] futex: replace bare barrier() with a READ_ONCE()
  2016-03-02  2:31       ` Jianyu Zhan
@ 2016-03-02  6:39         ` Darren Hart
  2016-03-02  7:12           ` Jianyu Zhan
  0 siblings, 1 reply; 7+ messages in thread
From: Darren Hart @ 2016-03-02  6:39 UTC (permalink / raw)
  To: Jianyu Zhan
  Cc: LKML, Thomas Gleixner, dave, Peter Zijlstra, Andrew Morton,
	Ingo Molnar, dvhart, bigeasy, Paul McKenney

On Wed, Mar 02, 2016 at 10:31:18AM +0800, Jianyu Zhan wrote:
> On Wed, Mar 2, 2016 at 9:37 AM, Darren Hart <dvhart@infradead.org> wrote:
> > read_once will use a *volatile assignment instead of calling barrier()
> > directly for a word size argument.
> >
> > With weak statements like "apparently" (above) and "could be" (from the original
> > post: This patch replaces this bare barrier() with a READ_ONCE(), a weaker form
> > of barrier(), which could be more informative.)" I do not see a compelling
> > reason to change what is notoriously fragile code with respect to barriers.
> >
> 
> 
> Fair enough.  The "apparently" wording is lame without assembly code evidence.
> I do not have such a s390 machine, so I have cc''ed the original
> author incorporating this barrier(),
> hopefully he could help test  this.
> 
> By "could be more informative"  I mean a READ_ONCE has explanatory
> effect by its name, instead of
> a bare barrier() without more inline comment for why.
> 
> As I said the retry code logic is effectively the same as
> 
> while (lock_ptr = READ_ONCE(q->lock_ptr)) {
>                    spin_lock(lock_ptr)
>                    if (unlikely(lock_ptr != q->lock_ptr)) {
>                          spin_unlock(lock_ptr);
>                    }
> 
>                    ...
> }
> 
> in which case READ_ONCE could perfectly fit, in that it will make
> compiler only read it once in every testing condition,
> which will eliminate the original problem that commit e91467ecd1ef
> addressed, though assembly code proof is needed.
> 
> Actually, the quotation I argued in previous mail could be used again
> here, from memory-barriers.txt:
> 
>  (*) The compiler is within its rights to merge successive loads from
>      the same variable.  Such merging can cause the compiler to "optimize"
>      the following code:
> 
>         while (tmp = a)
>                 do_something_with(tmp);
> 
>      into the following code, which, although in some sense legitimate
>      for single-threaded code, is almost certainly not what the developer
>      intended:
> 
>         if (tmp = a)
>                 for (;;)
>                         do_something_with(tmp);
> 
>      Use READ_ONCE() to prevent the compiler from doing this to you:
> 
>         while (tmp = READ_ONCE(a))
>                 do_something_with(tmp);
> 
> 
> I might be wrong, so I have cc'ed Paul, and Peter,  I wish they give comment :-)

I believe you are correct with respect to the retry and while condition being an
appropriate place for the application of READ_ONCE. The question is why is this
preferred to the existing barrier()? I suggest:

While barrier() is a fairly brute force general application of a compiler
barrier, READ_ONCE() is very specific, it targets only operations dealing with
the specified variable. As such, its application both clearly identifies the
volatile variable and frees the compiler to make optimizations a more general
barrier would forbid.


> 
> 
> > As for #2...
> >
> >> 2.  For the second problem I memtioned,  yes, it is theoretical,  and
> >> it is also due to  q->lock_ptr can change between
> >> the test of nullness of q->lock_ptr and the lock on q->lock_ptr.
> >>
> >> the code is
> >>
> >> retry:
> >>        lock_ptr = q->lock_ptr;
> >>        if (lock_ptr != 0)  {
> >>                   spin_lock(lock_ptr)
> >>                   if (unlikely(lock_ptr != q->lock_ptr)) {
> >>                         spin_unlock(lock_ptr);
> >>                          goto retry;
> >>                   }
> >>                    ...
> >>        }
> >>
> >> which is effectively the same as :
> >>
> >>  while (lock_ptr = q->lock_ptr) {
> >>                   spin_lock(lock_ptr)
> >>                   if (unlikely(lock_ptr != q->lock_ptr)) {
> >>                         spin_unlock(lock_ptr);
> >>                          goto retry;
> >>                   }
> >>                    ...
> >> }
> >>
> >> This might cause the compiler load the q->lock_ptr once and use it
> >> many times,  quoted from

Which is already covered by the barrier() in place today as a more general
compiler barrier.

Your argument is then simply that READ_ONCE is a more specific solution to the
problem.

> >> memory-barriers.txt:
> >>
> >>
> >>  (*) The compiler is within its rights to reload a variable, for example,
> >>     in cases where high register pressure prevents the compiler from
> >>     keeping all data of interest in registers.  The compiler might
> >>     therefore optimize the variable 'tmp' out of our previous example:
> >>
> >>        while (tmp = a)
> >>                do_something_with(tmp);
> >>
> >>     This could result in the following code, which is perfectly safe in
> >>     single-threaded code, but can be fatal in concurrent code:
> >>
> >>        while (a)
> >>                do_something_with(a);
> >>
> >>     For example, the optimized version of this code could result in
> >>     passing a zero to do_something_with() in the case where the variable
> >>     a was modified by some other CPU between the "while" statement and
> >>     the call to do_something_with().
> >>
> >>     Again, use READ_ONCE() to prevent the compiler from doing this:
> >>
> >>        while (tmp = READ_ONCE(a))
> >>                do_something_with(tmp);
> >>
> >
> > OK, so this is really the meat of the argument for the patch. You are looking to
> > add a compiler barrier instead of a CPU memory barrier. This should be what your

I was incorrect in my statement here. barrier() is a general compiler barrier and
READ_ONCE is a targeted compiler barrier (impacting only the operations dealing
with the specified variable). This helps the argument considerably.

> > commit message is focused on and it should provide compelling evidence to
> > justify risking the change.
> >
> > Compelling evidence for a compiler barrier would be a disassembly of the code
> > block before and after, demonstrating the compiler generating broken code and the
> > compiler generating correct code.
> >
> > In addition to this, however, I would want to see a strong convincing argument
> > that the READ_ONCE volatile cast is sufficient to cover the original case which
> > motivated the addition of the barrier() (not "apparently" and "could be").
> 
> As for #2, this is pure theoretical induction from this quotation, I
> do have no convincing argument
> and again I would like Paul to help clarify this.
> 
> 
> Thanks very much!
> 
> 
> Regards,
> Jianyu Zhan
> 

-- 
Darren Hart
Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] futex: replace bare barrier() with a READ_ONCE()
  2016-03-02  6:39         ` Darren Hart
@ 2016-03-02  7:12           ` Jianyu Zhan
  0 siblings, 0 replies; 7+ messages in thread
From: Jianyu Zhan @ 2016-03-02  7:12 UTC (permalink / raw)
  To: Darren Hart
  Cc: LKML, Thomas Gleixner, dave, Peter Zijlstra, Andrew Morton,
	Ingo Molnar, dvhart, bigeasy, Paul McKenney

On Wed, Mar 2, 2016 at 2:39 PM, Darren Hart <dvhart@infradead.org> wrote:
> I believe you are correct with respect to the retry and while condition being an
> appropriate place for the application of READ_ONCE. The question is why is this
> preferred to the existing barrier()? I suggest:
>
> While barrier() is a fairly brute force general application of a compiler
> barrier, READ_ONCE() is very specific, it targets only operations dealing with
> the specified variable. As such, its application both clearly identifies the
> volatile variable and frees the compiler to make optimizations a more general
> barrier would forbid.
>
>

Yep,  beside the informative point,  the more specifics of READ_ONCE
over barrier
is what I meant  "lightweight", I missed emphasizing this point.
Thanks for pointing it.

I will respin this patch to reflect this.

>>
>>
>> > As for #2...
>> >
>> >> 2.  For the second problem I memtioned,  yes, it is theoretical,  and
>> >> it is also due to  q->lock_ptr can change between
>> >> the test of nullness of q->lock_ptr and the lock on q->lock_ptr.
>> >>
>> >> the code is
>> >>
>> >> retry:
>> >>        lock_ptr = q->lock_ptr;
>> >>        if (lock_ptr != 0)  {
>> >>                   spin_lock(lock_ptr)
>> >>                   if (unlikely(lock_ptr != q->lock_ptr)) {
>> >>                         spin_unlock(lock_ptr);
>> >>                          goto retry;
>> >>                   }
>> >>                    ...
>> >>        }
>> >>
>> >> which is effectively the same as :
>> >>
>> >>  while (lock_ptr = q->lock_ptr) {
>> >>                   spin_lock(lock_ptr)
>> >>                   if (unlikely(lock_ptr != q->lock_ptr)) {
>> >>                         spin_unlock(lock_ptr);
>> >>                          goto retry;
>> >>                   }
>> >>                    ...
>> >> }
>> >>
>> >> This might cause the compiler load the q->lock_ptr once and use it
>> >> many times,  quoted from
>
> Which is already covered by the barrier() in place today as a more general
> compiler barrier.
>
> Your argument is then simply that READ_ONCE is a more specific solution to the
> problem.
>

Yep. And after re-thinking, I am now less convinced in this second
argument, since
it involves a comparison of q->lock_ptr in the loop body,  so this may
defeat any attempts
that compilers try to optimize the load out of the loop,  even without
a READ_ONCE().

But I will also incorporate this in the second submission for review .



Regards,
Jianyu Zhan

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-03-02  7:13 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-29 11:41 [PATCH] futex: replace bare barrier() with a READ_ONCE() Jianyu Zhan
2016-02-29 22:22 ` Darren Hart
2016-03-01  0:44   ` Jianyu Zhan
2016-03-02  1:37     ` Darren Hart
2016-03-02  2:31       ` Jianyu Zhan
2016-03-02  6:39         ` Darren Hart
2016-03-02  7:12           ` Jianyu Zhan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.