All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] seqlock: fix raw_read_seqcount_latch()
@ 2016-05-21 20:14 Alexey Dobriyan
  2016-05-22 10:48 ` Peter Zijlstra
  2016-05-27 11:11 ` [PATCH] seqlock: fix raw_read_seqcount_latch() Peter Zijlstra
  0 siblings, 2 replies; 12+ messages in thread
From: Alexey Dobriyan @ 2016-05-21 20:14 UTC (permalink / raw)
  To: akpm; +Cc: peterz, linux-kernel

lockless_dereference() is supposed to take pointer not integer.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 include/linux/seqlock.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -277,7 +277,7 @@ static inline void raw_write_seqcount_barrier(seqcount_t *s)
 
 static inline int raw_read_seqcount_latch(seqcount_t *s)
 {
-	return lockless_dereference(s->sequence);
+	return lockless_dereference(s)->sequence;
 }
 
 /**
@@ -331,7 +331,7 @@ static inline int raw_read_seqcount_latch(seqcount_t *s)
  *	unsigned seq, idx;
  *
  *	do {
- *		seq = lockless_dereference(latch->seq);
+ *		seq = lockless_dereference(latch)->seq;
  *
  *		idx = seq & 0x01;
  *		entry = data_query(latch->data[idx], ...);

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

* Re: [PATCH] seqlock: fix raw_read_seqcount_latch()
  2016-05-21 20:14 [PATCH] seqlock: fix raw_read_seqcount_latch() Alexey Dobriyan
@ 2016-05-22 10:48 ` Peter Zijlstra
  2016-05-22 18:50   ` Alexey Dobriyan
                     ` (2 more replies)
  2016-05-27 11:11 ` [PATCH] seqlock: fix raw_read_seqcount_latch() Peter Zijlstra
  1 sibling, 3 replies; 12+ messages in thread
From: Peter Zijlstra @ 2016-05-22 10:48 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: akpm, linux-kernel, Paul McKenney

On Sat, May 21, 2016 at 11:14:49PM +0300, Alexey Dobriyan wrote:
> lockless_dereference() is supposed to take pointer not integer.

Urgh :/

Is there any way we can make lockless_dereference() issue a warning if
we don't feed it a pointer?

Would something like so work? All pointer types should silently cast to
void * while integer (and others) should refuse to.

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index b5ff9881bef8..8886de704d33 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -544,6 +544,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  */
 #define lockless_dereference(p) \
 ({ \
+ 	__maybe_unused void * _________p2 = p; \
 	typeof(p) _________p1 = READ_ONCE(p); \
 	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
 	(_________p1); \

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

* Re: [PATCH] seqlock: fix raw_read_seqcount_latch()
  2016-05-22 10:48 ` Peter Zijlstra
@ 2016-05-22 18:50   ` Alexey Dobriyan
  2016-05-23  9:36     ` Peter Zijlstra
  2016-06-03 10:58   ` [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type tip-bot for Peter Zijlstra
  2016-06-08 14:19   ` tip-bot for Peter Zijlstra
  2 siblings, 1 reply; 12+ messages in thread
From: Alexey Dobriyan @ 2016-05-22 18:50 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: akpm, linux-kernel, Paul McKenney

On Sun, May 22, 2016 at 12:48:27PM +0200, Peter Zijlstra wrote:
> On Sat, May 21, 2016 at 11:14:49PM +0300, Alexey Dobriyan wrote:
> > lockless_dereference() is supposed to take pointer not integer.
> 
> Urgh :/
> 
> Is there any way we can make lockless_dereference() issue a warning if
> we don't feed it a pointer?
> 
> Would something like so work? All pointer types should silently cast to
> void * while integer (and others) should refuse to.

This works (and spammy enough in case of seqlock, which is good)
but not for "unsigned long":

	include/linux/percpu-refcount.h:146:36: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
	  percpu_ptr = lockless_dereference(ref->percpu_count_ptr);

> --- a/include/linux/compiler.h
> +++ b/include/linux/compiler.h
> @@ -544,6 +544,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
>   */
>  #define lockless_dereference(p) \
>  ({ \
> + 	__maybe_unused void * _________p2 = p; \
>  	typeof(p) _________p1 = READ_ONCE(p); \
>  	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
>  	(_________p1); \

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

* Re: [PATCH] seqlock: fix raw_read_seqcount_latch()
  2016-05-22 18:50   ` Alexey Dobriyan
@ 2016-05-23  9:36     ` Peter Zijlstra
  2016-05-25 19:57       ` Tejun Heo
  0 siblings, 1 reply; 12+ messages in thread
From: Peter Zijlstra @ 2016-05-23  9:36 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: akpm, linux-kernel, Paul McKenney, Tejun Heo

On Sun, May 22, 2016 at 09:50:40PM +0300, Alexey Dobriyan wrote:
> On Sun, May 22, 2016 at 12:48:27PM +0200, Peter Zijlstra wrote:
> > On Sat, May 21, 2016 at 11:14:49PM +0300, Alexey Dobriyan wrote:
> > > lockless_dereference() is supposed to take pointer not integer.
> > 
> > Urgh :/
> > 
> > Is there any way we can make lockless_dereference() issue a warning if
> > we don't feed it a pointer?
> > 
> > Would something like so work? All pointer types should silently cast to
> > void * while integer (and others) should refuse to.
> 
> This works (and spammy enough in case of seqlock, which is good)
> but not for "unsigned long":
> 
> 	include/linux/percpu-refcount.h:146:36: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
> 	  percpu_ptr = lockless_dereference(ref->percpu_count_ptr);

TJ; would you prefer casting or not using lockless_dereference() here?

> 
> > --- a/include/linux/compiler.h
> > +++ b/include/linux/compiler.h
> > @@ -544,6 +544,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
> >   */
> >  #define lockless_dereference(p) \
> >  ({ \
> > + 	__maybe_unused void * _________p2 = p; \
> >  	typeof(p) _________p1 = READ_ONCE(p); \
> >  	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
> >  	(_________p1); \

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

* Re: [PATCH] seqlock: fix raw_read_seqcount_latch()
  2016-05-23  9:36     ` Peter Zijlstra
@ 2016-05-25 19:57       ` Tejun Heo
  2016-05-25 20:11         ` [PATCH] percpu: Revert ("percpu: Replace smp_read_barrier_depends() with lockless_dereference()") Tejun Heo
  0 siblings, 1 reply; 12+ messages in thread
From: Tejun Heo @ 2016-05-25 19:57 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Alexey Dobriyan, akpm, linux-kernel, Paul McKenney

Hello,

On Mon, May 23, 2016 at 11:36:18AM +0200, Peter Zijlstra wrote:
> > 	include/linux/percpu-refcount.h:146:36: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
> > 	  percpu_ptr = lockless_dereference(ref->percpu_count_ptr);
> 
> TJ; would you prefer casting or not using lockless_dereference() here?

Casting is nasty - *(unsigned long __percpu **)& - because the macro
expects an lvalue.  I think it'd be better to revert to opencoding
READ_ONCE() and barrier there.  It's a pretty special case anyway.

Thanks.

-- 
tejun

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

* [PATCH] percpu: Revert ("percpu: Replace smp_read_barrier_depends() with lockless_dereference()")
  2016-05-25 19:57       ` Tejun Heo
@ 2016-05-25 20:11         ` Tejun Heo
  0 siblings, 0 replies; 12+ messages in thread
From: Tejun Heo @ 2016-05-25 20:11 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Alexey Dobriyan, akpm, linux-kernel, Paul McKenney,
	Pranith Kumar, kernel-team

lockless_dereference() is planned to grow a sanity check to ensure
that the input parameter is a pointer.  __ref_is_percpu() passes in an
unsinged long value which is a combination of a pointer and a flag.
While it can be casted to a pointer lvalue, the casting looks messy
and it's a special case anyway.  Let's revert back to open-coding
READ_ONCE() and explicit barrier.

This doesn't cause any functional changes.

Signed-off-by: Tejun Heo <tj@kernel.org>
Link: http://lkml.kernel.org/g/20160522185040.GA23664@p183.telecom.by
Cc: Pranith Kumar <bobby.prani@gmail.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
---
So, something like this.  Please feel free to include in the series.

Thanks.

 include/linux/percpu-refcount.h |   12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index 84f542d..1c7eec0 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -136,14 +136,12 @@ static inline bool __ref_is_percpu(struct percpu_ref *ref,
 	 * used as a pointer.  If the compiler generates a separate fetch
 	 * when using it as a pointer, __PERCPU_REF_ATOMIC may be set in
 	 * between contaminating the pointer value, meaning that
-	 * ACCESS_ONCE() is required when fetching it.
-	 *
-	 * Also, we need a data dependency barrier to be paired with
-	 * smp_store_release() in __percpu_ref_switch_to_percpu().
-	 *
-	 * Use lockless deref which contains both.
+	 * READ_ONCE() is required when fetching it.
 	 */
-	percpu_ptr = lockless_dereference(ref->percpu_count_ptr);
+	percpu_ptr = READ_ONCE(ref->percpu_count_ptr);
+
+	/* paired with smp_store_release() in __percpu_ref_switch_to_percpu() */
+	smp_read_barrier_depends();
 
 	/*
 	 * Theoretically, the following could test just ATOMIC; however,

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

* Re: [PATCH] seqlock: fix raw_read_seqcount_latch()
  2016-05-21 20:14 [PATCH] seqlock: fix raw_read_seqcount_latch() Alexey Dobriyan
  2016-05-22 10:48 ` Peter Zijlstra
@ 2016-05-27 11:11 ` Peter Zijlstra
  2016-06-03 10:46   ` [tip:locking/core] locking/seqcount: Re-fix raw_read_seqcount_latch() tip-bot for Peter Zijlstra
  1 sibling, 1 reply; 12+ messages in thread
From: Peter Zijlstra @ 2016-05-27 11:11 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: akpm, linux-kernel, Paul McKenney

On Sat, May 21, 2016 at 11:14:49PM +0300, Alexey Dobriyan wrote:
> lockless_dereference() is supposed to take pointer not integer.
> 
> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
> ---
> 
>  include/linux/seqlock.h |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> --- a/include/linux/seqlock.h
> +++ b/include/linux/seqlock.h
> @@ -277,7 +277,7 @@ static inline void raw_write_seqcount_barrier(seqcount_t *s)
>  
>  static inline int raw_read_seqcount_latch(seqcount_t *s)
>  {
> -	return lockless_dereference(s->sequence);
> +	return lockless_dereference(s)->sequence;
>  }
>  
>  /**
> @@ -331,7 +331,7 @@ static inline int raw_read_seqcount_latch(seqcount_t *s)
>   *	unsigned seq, idx;
>   *
>   *	do {
> - *		seq = lockless_dereference(latch->seq);
> + *		seq = lockless_dereference(latch)->seq;
>   *
>   *		idx = seq & 0x01;
>   *		entry = data_query(latch->data[idx], ...);

So while the code was dubious; I it is now wrong, but my head hurts.

I'll queue the below, TJs per-cpu change and the lockless_dereference()
void * cast trick.


---
Subject: seqcount: Re-fix raw_read_seqcount_latch()

Commit 50755bc1c305 ("seqlock: fix raw_read_seqcount_latch()") broke
raw_read_seqcount_latch().

If you look at the comment that was modified; the thing that changes is
the seq count, not the latch pointer.

 * void latch_modify(struct latch_struct *latch, ...)
 * {
 *	smp_wmb();	<- Ensure that the last data[1] update is visible
 *	latch->seq++;
 *	smp_wmb();	<- Ensure that the seqcount update is visible
 *
 *	modify(latch->data[0], ...);
 *
 *	smp_wmb();	<- Ensure that the data[0] update is visible
 *	latch->seq++;
 *	smp_wmb();	<- Ensure that the seqcount update is visible
 *
 *	modify(latch->data[1], ...);
 * }
 *
 * The query will have a form like:
 *
 * struct entry *latch_query(struct latch_struct *latch, ...)
 * {
 *	struct entry *entry;
 *	unsigned seq, idx;
 *
 *	do {
 *		seq = lockless_dereference(latch->seq);

So here we have:

		seq = READ_ONCE(latch->seq);
		smp_read_barrier_depends();

Which is exactly what we want; the new code:

		seq = ({ p = READ_ONCE(latch);
			 smp_read_barrier_depends(); p })->seq;

is just wrong; because it looses the volatile read on seq, which can now
be torn or worse 'optimized'. And the read_depend barrier is also placed
wrong, we want it after the load of seq, to match the above data[]
up-to-date wmb()s.

Such that when we dereference latch->data[] below, we're guaranteed to
observe the right data.

 *
 *		idx = seq & 0x01;
 *		entry = data_query(latch->data[idx], ...);
 *
 *		smp_rmb();
 *	} while (seq != latch->seq);
 *
 *	return entry;
 * }

So yes, not passing a pointer is not pretty, but the code was correct,
and isn't anymore now.

Change to explicit READ_ONCE()+smp_read_barrier_depends() to avoid
confusion and allow strict lockless_dereference() checking.

Fixes: 50755bc1c305 ("seqlock: fix raw_read_seqcount_latch()")
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
 include/linux/seqlock.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 7973a821ac58..f3db247cebc8 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -277,7 +277,9 @@ static inline void raw_write_seqcount_barrier(seqcount_t *s)
 
 static inline int raw_read_seqcount_latch(seqcount_t *s)
 {
-	return lockless_dereference(s)->sequence;
+	int seq = READ_ONCE(s->sequence);
+	smp_read_barrier_depends();
+	return seq;
 }
 
 /**
@@ -331,7 +333,7 @@ static inline int raw_read_seqcount_latch(seqcount_t *s)
  *	unsigned seq, idx;
  *
  *	do {
- *		seq = lockless_dereference(latch)->seq;
+ *		seq = raw_read_seqcount_latch(&latch->seq);
  *
  *		idx = seq & 0x01;
  *		entry = data_query(latch->data[idx], ...);

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

* [tip:locking/core] locking/seqcount: Re-fix raw_read_seqcount_latch()
  2016-05-27 11:11 ` [PATCH] seqlock: fix raw_read_seqcount_latch() Peter Zijlstra
@ 2016-06-03 10:46   ` tip-bot for Peter Zijlstra
  0 siblings, 0 replies; 12+ messages in thread
From: tip-bot for Peter Zijlstra @ 2016-06-03 10:46 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: peterz, adobriyan, hpa, paulmck, linux-kernel, torvalds, tglx,
	akpm, mingo

Commit-ID:  55eed755c6e30a89be3a791a6b0ad208aadd9bdc
Gitweb:     http://git.kernel.org/tip/55eed755c6e30a89be3a791a6b0ad208aadd9bdc
Author:     Peter Zijlstra <peterz@infradead.org>
AuthorDate: Fri, 27 May 2016 13:11:17 +0200
Committer:  Ingo Molnar <mingo@kernel.org>
CommitDate: Fri, 3 Jun 2016 08:37:25 +0200

locking/seqcount: Re-fix raw_read_seqcount_latch()

Commit 50755bc1c305 ("seqlock: fix raw_read_seqcount_latch()") broke
raw_read_seqcount_latch().

If you look at the comment that was modified; the thing that changes is
the seq count, not the latch pointer.

 * void latch_modify(struct latch_struct *latch, ...)
 * {
 *	smp_wmb();	<- Ensure that the last data[1] update is visible
 *	latch->seq++;
 *	smp_wmb();	<- Ensure that the seqcount update is visible
 *
 *	modify(latch->data[0], ...);
 *
 *	smp_wmb();	<- Ensure that the data[0] update is visible
 *	latch->seq++;
 *	smp_wmb();	<- Ensure that the seqcount update is visible
 *
 *	modify(latch->data[1], ...);
 * }
 *
 * The query will have a form like:
 *
 * struct entry *latch_query(struct latch_struct *latch, ...)
 * {
 *	struct entry *entry;
 *	unsigned seq, idx;
 *
 *	do {
 *		seq = lockless_dereference(latch->seq);

So here we have:

		seq = READ_ONCE(latch->seq);
		smp_read_barrier_depends();

Which is exactly what we want; the new code:

		seq = ({ p = READ_ONCE(latch);
			 smp_read_barrier_depends(); p })->seq;

is just wrong; because it looses the volatile read on seq, which can now
be torn or worse 'optimized'. And the read_depend barrier is also placed
wrong, we want it after the load of seq, to match the above data[]
up-to-date wmb()s.

Such that when we dereference latch->data[] below, we're guaranteed to
observe the right data.

 *
 *		idx = seq & 0x01;
 *		entry = data_query(latch->data[idx], ...);
 *
 *		smp_rmb();
 *	} while (seq != latch->seq);
 *
 *	return entry;
 * }

So yes, not passing a pointer is not pretty, but the code was correct,
and isn't anymore now.

Change to explicit READ_ONCE()+smp_read_barrier_depends() to avoid
confusion and allow strict lockless_dereference() checking.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: 50755bc1c305 ("seqlock: fix raw_read_seqcount_latch()")
Link: http://lkml.kernel.org/r/20160527111117.GL3192@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 include/linux/seqlock.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 7973a82..ead9765 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -277,7 +277,10 @@ static inline void raw_write_seqcount_barrier(seqcount_t *s)
 
 static inline int raw_read_seqcount_latch(seqcount_t *s)
 {
-	return lockless_dereference(s)->sequence;
+	int seq = READ_ONCE(s->sequence);
+	/* Pairs with the first smp_wmb() in raw_write_seqcount_latch() */
+	smp_read_barrier_depends();
+	return seq;
 }
 
 /**
@@ -331,7 +334,7 @@ static inline int raw_read_seqcount_latch(seqcount_t *s)
  *	unsigned seq, idx;
  *
  *	do {
- *		seq = lockless_dereference(latch)->seq;
+ *		seq = raw_read_seqcount_latch(&latch->seq);
  *
  *		idx = seq & 0x01;
  *		entry = data_query(latch->data[idx], ...);

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

* [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type
  2016-05-22 10:48 ` Peter Zijlstra
  2016-05-22 18:50   ` Alexey Dobriyan
@ 2016-06-03 10:58   ` tip-bot for Peter Zijlstra
  2016-06-06 21:31     ` Mateusz Guzik
  2016-06-08 14:19   ` tip-bot for Peter Zijlstra
  2 siblings, 1 reply; 12+ messages in thread
From: tip-bot for Peter Zijlstra @ 2016-06-03 10:58 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: paulmck, akpm, torvalds, adobriyan, tglx, linux-kernel, mingo,
	hpa, peterz

Commit-ID:  25841ee0e9d2a1d952828138416701f20ea831eb
Gitweb:     http://git.kernel.org/tip/25841ee0e9d2a1d952828138416701f20ea831eb
Author:     Peter Zijlstra <peterz@infradead.org>
AuthorDate: Sun, 22 May 2016 12:48:27 +0200
Committer:  Ingo Molnar <mingo@kernel.org>
CommitDate: Fri, 3 Jun 2016 12:06:11 +0200

locking/barriers: Validate lockless_dereference() is used on a pointer type

Add a cast to void * to validate the argument @p is indeed a pointer.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160522104827.GP3193@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 include/linux/compiler.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 793c082..e9c6417 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -545,9 +545,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  * Similar to rcu_dereference(), but for situations where the pointed-to
  * object's lifetime is managed by something other than RCU.  That
  * "something other" might be reference counting or simple immortality.
+ *
+ * The seemingly unused void * variable is to validate @p is indeed a pointer
+ * type. All pointer types silently cast to void *.
  */
 #define lockless_dereference(p) \
 ({ \
+	__maybe_unused const void * const _________p2 = p; \
 	typeof(p) _________p1 = READ_ONCE(p); \
 	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
 	(_________p1); \

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

* Re: [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type
  2016-06-03 10:58   ` [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type tip-bot for Peter Zijlstra
@ 2016-06-06 21:31     ` Mateusz Guzik
  2016-06-07  7:10       ` Peter Zijlstra
  0 siblings, 1 reply; 12+ messages in thread
From: Mateusz Guzik @ 2016-06-06 21:31 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-tip-commits, paulmck, akpm, torvalds, adobriyan, tglx,
	linux-kernel, mingo, hpa, peterz

On Fri, Jun 03, 2016 at 03:58:09AM -0700, tip-bot for Peter Zijlstra wrote:
> Commit-ID:  25841ee0e9d2a1d952828138416701f20ea831eb
> Gitweb:     http://git.kernel.org/tip/25841ee0e9d2a1d952828138416701f20ea831eb
> Author:     Peter Zijlstra <peterz@infradead.org>
> AuthorDate: Sun, 22 May 2016 12:48:27 +0200
> Committer:  Ingo Molnar <mingo@kernel.org>
> CommitDate: Fri, 3 Jun 2016 12:06:11 +0200
> 
> locking/barriers: Validate lockless_dereference() is used on a pointer type
> 
> Add a cast to void * to validate the argument @p is indeed a pointer.
> 
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Cc: Alexey Dobriyan <adobriyan@gmail.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Link: http://lkml.kernel.org/r/20160522104827.GP3193@twins.programming.kicks-ass.net
> Signed-off-by: Ingo Molnar <mingo@kernel.org>
> ---
>  include/linux/compiler.h | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/include/linux/compiler.h b/include/linux/compiler.h
> index 793c082..e9c6417 100644
> --- a/include/linux/compiler.h
> +++ b/include/linux/compiler.h
> @@ -545,9 +545,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
>   * Similar to rcu_dereference(), but for situations where the pointed-to
>   * object's lifetime is managed by something other than RCU.  That
>   * "something other" might be reference counting or simple immortality.
> + *
> + * The seemingly unused void * variable is to validate @p is indeed a pointer
> + * type. All pointer types silently cast to void *.
>   */
>  #define lockless_dereference(p) \
>  ({ \
> +	__maybe_unused const void * const _________p2 = p; \
>  	typeof(p) _________p1 = READ_ONCE(p); \
>  	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
>  	(_________p1); \


This causes issues, e.g.:
BUG: KASAN: user-memory-access on address 000060ff95001931^M
Read of size 1 by task NetworkManager/897^M
CPU: 1 PID: 897 Comm: NetworkManager Not tainted 4.7.0-rc1dupa+ #355^M
Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011^M
 ffff88003a1f8040 0000000017d08b23 ffff880033aff4b0 ffffffff8187b2f8^M
 ffff88005b44f2c8 ffff880033aff548 ffff880033aff538 ffffffff813506a6^M
 ffffffff81167e5esystemd[1]: sshd.service: Forked /usr/sbin/sshd as 904^M
^M
 ffffed000675fe9d 0000000000000286 ffff880033aff588^M
Call Trace:^M
 [<ffffffff8187b2f8>] dump_stack+0x85/0xcd^M
 [<ffffffff813506a6>] kasan_report_error+0x456/0x560^M
 [<ffffffff81167e5e>] ? vprintk_default+0x3e/0x60^M
 [<ffffffff812a19e3>] ? printk+0xa8/0xd8^M
 [<ffffffff812a193b>] ? power_down+0xa9/0xa9^M
 [<ffffffff81350d48>] kasan_report+0x58/0x60^M
 [<ffffffff81e84fe5>] ? leaf_walk_rcu+0x235/0x2d0^M
 [<ffffffff8134f447>] __asan_load1+0x47/0x50^M
 [<ffffffff81e84fe5>] leaf_walk_rcu+0x235/0x2d0^M
[snip]

The reason is that leaf_walk_rcu does get_child_rcu(pn, cindex++), which
ends up in lockless_dereference as pn[cindex++], which is now evaluated
twice. 

The simplest fix I see does the assignment later, that is:
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index e9c6417..06f27fd 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -551,8 +551,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  */
 #define lockless_dereference(p) \
 ({ \
-       __maybe_unused const void * const _________p2 = p; \
        typeof(p) _________p1 = READ_ONCE(p); \
+       __maybe_unused const void * const _________p2 = _________p1; \
        smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
        (_________p1); \
 })

-- 
Mateusz Guzik

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

* Re: [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type
  2016-06-06 21:31     ` Mateusz Guzik
@ 2016-06-07  7:10       ` Peter Zijlstra
  0 siblings, 0 replies; 12+ messages in thread
From: Peter Zijlstra @ 2016-06-07  7:10 UTC (permalink / raw)
  To: Mateusz Guzik
  Cc: linux-tip-commits, paulmck, akpm, torvalds, adobriyan, tglx,
	linux-kernel, mingo, hpa

On Mon, Jun 06, 2016 at 11:31:39PM +0200, Mateusz Guzik wrote:
> The reason is that leaf_walk_rcu does get_child_rcu(pn, cindex++), which
> ends up in lockless_dereference as pn[cindex++], which is now evaluated
> twice. 

Indeed, bad that; yes I think the below will work, will you send a
proper patch so I can apply?

> The simplest fix I see does the assignment later, that is:
> diff --git a/include/linux/compiler.h b/include/linux/compiler.h
> index e9c6417..06f27fd 100644
> --- a/include/linux/compiler.h
> +++ b/include/linux/compiler.h
> @@ -551,8 +551,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
>   */
>  #define lockless_dereference(p) \
>  ({ \
> -       __maybe_unused const void * const _________p2 = p; \
>         typeof(p) _________p1 = READ_ONCE(p); \
> +       __maybe_unused const void * const _________p2 = _________p1; \
>         smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
>         (_________p1); \
>  })
> 
> -- 
> Mateusz Guzik

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

* [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type
  2016-05-22 10:48 ` Peter Zijlstra
  2016-05-22 18:50   ` Alexey Dobriyan
  2016-06-03 10:58   ` [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type tip-bot for Peter Zijlstra
@ 2016-06-08 14:19   ` tip-bot for Peter Zijlstra
  2 siblings, 0 replies; 12+ messages in thread
From: tip-bot for Peter Zijlstra @ 2016-06-08 14:19 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: tglx, peterz, akpm, hpa, paulmck, adobriyan, mingo, torvalds,
	linux-kernel

Commit-ID:  331b6d8c7afc2e5b900b9dcd850c265e1ba8d8e7
Gitweb:     http://git.kernel.org/tip/331b6d8c7afc2e5b900b9dcd850c265e1ba8d8e7
Author:     Peter Zijlstra <peterz@infradead.org>
AuthorDate: Sun, 22 May 2016 12:48:27 +0200
Committer:  Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 8 Jun 2016 14:22:47 +0200

locking/barriers: Validate lockless_dereference() is used on a pointer type

Use the type to validate the argument @p is indeed a pointer type.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160522104827.GP3193@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 include/linux/compiler.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 793c082..06f27fd 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -545,10 +545,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  * Similar to rcu_dereference(), but for situations where the pointed-to
  * object's lifetime is managed by something other than RCU.  That
  * "something other" might be reference counting or simple immortality.
+ *
+ * The seemingly unused void * variable is to validate @p is indeed a pointer
+ * type. All pointer types silently cast to void *.
  */
 #define lockless_dereference(p) \
 ({ \
 	typeof(p) _________p1 = READ_ONCE(p); \
+	__maybe_unused const void * const _________p2 = _________p1; \
 	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
 	(_________p1); \
 })

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

end of thread, other threads:[~2016-06-08 14:20 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-21 20:14 [PATCH] seqlock: fix raw_read_seqcount_latch() Alexey Dobriyan
2016-05-22 10:48 ` Peter Zijlstra
2016-05-22 18:50   ` Alexey Dobriyan
2016-05-23  9:36     ` Peter Zijlstra
2016-05-25 19:57       ` Tejun Heo
2016-05-25 20:11         ` [PATCH] percpu: Revert ("percpu: Replace smp_read_barrier_depends() with lockless_dereference()") Tejun Heo
2016-06-03 10:58   ` [tip:locking/core] locking/barriers: Validate lockless_dereference() is used on a pointer type tip-bot for Peter Zijlstra
2016-06-06 21:31     ` Mateusz Guzik
2016-06-07  7:10       ` Peter Zijlstra
2016-06-08 14:19   ` tip-bot for Peter Zijlstra
2016-05-27 11:11 ` [PATCH] seqlock: fix raw_read_seqcount_latch() Peter Zijlstra
2016-06-03 10:46   ` [tip:locking/core] locking/seqcount: Re-fix raw_read_seqcount_latch() tip-bot for Peter Zijlstra

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.