Skip to contentSkip to conversation

kernel: events: core: Replace rcu_assign_pointer() with RCU_INIT_POINTER()

PATCH In review Andreea-Cristina Bernat 4 participants 8 messages Aug 22, 2014 – Sep 28, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 kernel: events: core: Replace rcu_assign_pointer() with RCU_INIT_POINTER()

The use of "rcu_assign_pointer()" is NULLing out the pointer. According to RCU_INIT_POINTER()'s block comment:
"1. This use of RCU_INIT_POINTER() is NULLing out the pointer"
it is better to use it instead of rcu_assign_pointer() because it has a smaller overhead.

The following Coccinelle semantic patch was used:
@@
@@

- rcu_assign_pointer
+ RCU_INIT_POINTER
(..., NULL)

---
 kernel/events/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/events/core.c +1 -1
index 0d735be..4b84dd5 100644
@@ -5744,7 +5744,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
 	if (!hlist)
 		return;
 
-	rcu_assign_pointer(swhash->swevent_hlist, NULL);
+	RCU_INIT_POINTER(swhash->swevent_hlist, NULL);
 	kfree_rcu(hlist, rcu_head);
 }
 
Signature · 1 line
1.9.1
maintainer
#1 lore raw
Quoted 24 lines · Andreea-Cristina Bernat

The use of "rcu_assign_pointer()" is NULLing out the pointer. According to RCU_INIT_POINTER()'s block comment:
"1. This use of RCU_INIT_POINTER() is NULLing out the pointer"
it is better to use it instead of rcu_assign_pointer() because it has a smaller overhead.

The following Coccinelle semantic patch was used:
@@
@@

- rcu_assign_pointer
+ RCU_INIT_POINTER
(..., NULL)

---
 kernel/events/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/events/core.c +0 -0
index 0d735be..4b84dd5 100644

kernel/events/core.c static void swevent_hlist_release(struct swevent_htable *swhash) · line 5749

Quoted 7 lines
kernel/events/core.c +1 -1
@@ -5744,7 +5744,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
 	if (!hlist)
 		return;
 
-	rcu_assign_pointer(swhash->swevent_hlist, NULL);
+	RCU_INIT_POINTER(swhash->swevent_hlist, NULL);
 	kfree_rcu(hlist, rcu_head);
 }

Paul, why not do something like the below and do away with all this nonsense?

---
 include/linux/rcupdate.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
include/linux/rcupdate.h +7 -1
index d231aa17b1d7..38c3e629ae70 100644
@@ -623,7 +623,13 @@ static inline void rcu_preempt_sleep_check(void)
  * please be careful when making changes to rcu_assign_pointer() and the
  * other macros that it invokes.
  */
-#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v))
+#define rcu_assign_pointer(p, v)					\
+do {									\
+	if (__builtin_constant_p(v) && v == NULL)			\
+		p = RCU_INITIALIZER(v);					\
+	else								\
+		smp_store_release(&p, RCU_INITIALIZER(v));		\
+} while (0)
 
 /**
  * rcu_access_pointer() - fetch RCU pointer with no dereferencing
#2 lore raw
Quoted 28 lines · Peter Zijlstra
Quoted 27 lines · Andreea-Cristina Bernat

The use of "rcu_assign_pointer()" is NULLing out the pointer. According to RCU_INIT_POINTER()'s block comment:
"1. This use of RCU_INIT_POINTER() is NULLing out the pointer"
it is better to use it instead of rcu_assign_pointer() because it has a smaller overhead.

The following Coccinelle semantic patch was used:
@@
@@

- rcu_assign_pointer
+ RCU_INIT_POINTER
(..., NULL)

---
 kernel/events/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/events/core.c +0 -0
index 0d735be..4b84dd5 100644
@@ -5744,7 +5744,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
 	if (!hlist)
 		return;
 
Quoted 7 lines

kernel/events/core.c static void swevent_hlist_release(struct swevent_htable *swhash) · line 5749

Quoted 4 lines
kernel/events/core.c +1 -1
-	rcu_assign_pointer(swhash->swevent_hlist, NULL);
+	RCU_INIT_POINTER(swhash->swevent_hlist, NULL);
 	kfree_rcu(hlist, rcu_head);
 }

Paul, why not do something like the below and do away with all this nonsense?

We used to do that, but the compilers became uncooperative, despite Stephen Hemminger's best efforts.

Thanx, Paul

Quoted 23 lines
---
 include/linux/rcupdate.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
include/linux/rcupdate.h +7 -1
index d231aa17b1d7..38c3e629ae70 100644
@@ -623,7 +623,13 @@ static inline void rcu_preempt_sleep_check(void)
  * please be careful when making changes to rcu_assign_pointer() and the
  * other macros that it invokes.
  */
-#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v))
+#define rcu_assign_pointer(p, v)					\
+do {									\
+	if (__builtin_constant_p(v) && v == NULL)			\
+		p = RCU_INITIALIZER(v);					\
+	else								\
+		smp_store_release(&p, RCU_INITIALIZER(v));		\
+} while (0)
 
 /**
  * rcu_access_pointer() - fetch RCU pointer with no dereferencing
maintainer
#3 lore raw
Quoted 7 lines · Paul E. McKenney
Quoted 2 lines · Peter Zijlstra

Paul, why not do something like the below and do away with all this nonsense?

We used to do that, but the compilers became uncooperative, despite Stephen Hemminger's best efforts.

Happen to have a link handy to that thread so I can educate myself?

#4 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Quoted 2 lines · Peter Zijlstra

Paul, why not do something like the below and do away with all this nonsense?

We used to do that, but the compilers became uncooperative, despite Stephen Hemminger's best efforts.

Happen to have a link handy to that thread so I can educate myself?

After a bit of software archeology, here you go...

Commit d322f45ceed52 (rcu: Make rcu_assign_pointer() unconditionally insert a memory barrier) made this change. According to the commit log:

Recent changes to gcc give warning messages on rcu_assign_pointers()'s checks that allow it to determine when it is OK to omit the memory barrier. Stephen Hemminger tried a number of gcc tricks to silence this warning, but #pragmas and CPP macros do not work together in the way that would be required to make this work.

This was applied in 2011, and searching LKML during that time gives the following: https://lkml.org/lkml/2011/7/29/305

And in this LKML post, Stephen Hemminger wrote:

Gcc now generates warnings from rcu_assign_pointer when passed the address of something for example:
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
This warning is harmless and should be surpressed but there maybe other cases where we want that Gcc warning.

I tried various combinations of in rcu_assign_pointer macro
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
...
#pragma GCC diagnostic pop
but macro's and pragma's don't nest with the correct scope for this.

Maybe some one with more Gcc foo and time to waste could take a crack at it.

Adding Stephen on CC in case he remembers more.

Thanx, Paul

maintainer
#5 lore raw
Quoted 43 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Quoted 2 lines · Peter Zijlstra

Paul, why not do something like the below and do away with all this nonsense?

We used to do that, but the compilers became uncooperative, despite Stephen Hemminger's best efforts.

Happen to have a link handy to that thread so I can educate myself?

After a bit of software archeology, here you go...

Commit d322f45ceed52 (rcu: Make rcu_assign_pointer() unconditionally insert a memory barrier) made this change. According to the commit log:

Recent changes to gcc give warning messages on rcu_assign_pointers()'s checks that allow it to determine when it is OK to omit the memory barrier. Stephen Hemminger tried a number of gcc tricks to silence this warning, but #pragmas and CPP macros do not work together in the way that would be required to make this work.

This was applied in 2011, and searching LKML during that time gives the following: https://lkml.org/lkml/2011/7/29/305

And in this LKML post, Stephen Hemminger wrote:

Gcc now generates warnings from rcu_assign_pointer when passed the address of something for example:
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
This warning is harmless and should be surpressed but there maybe other cases where we want that Gcc warning.

I tried various combinations of in rcu_assign_pointer macro
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
...
#pragma GCC diagnostic pop
but macro's and pragma's don't nest with the correct scope for this.

Quoted 4 lines

Maybe some one with more Gcc foo and time to waste could take a crack at it.

Adding Stephen on CC in case he remembers more.

So I read all that and am still left wondering WTF the problem was :/

I googled a bit and found this thread:

https://lkml.org/lkml/2014/3/24/39

Where Michael actually has two 'fixes' to the problem. Instead we continue clutter the API with this silly RCU_INIT_POINTER stuff, totally sad.

But nowhere have I found the actual warning GCC gives, I suppose I can go change my local tree and compile some code to obtain it, but that seems backwards. The patch 'working' around that should have mentioned it and explained why the warning is bogus or not.

#6 lore raw
Quoted 51 lines · Peter Zijlstra
Quoted 43 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Quoted 2 lines · Peter Zijlstra

Paul, why not do something like the below and do away with all this nonsense?

We used to do that, but the compilers became uncooperative, despite Stephen Hemminger's best efforts.

Happen to have a link handy to that thread so I can educate myself?

After a bit of software archeology, here you go...

Commit d322f45ceed52 (rcu: Make rcu_assign_pointer() unconditionally insert a memory barrier) made this change. According to the commit log:

Recent changes to gcc give warning messages on rcu_assign_pointers()'s checks that allow it to determine when it is OK to omit the memory barrier. Stephen Hemminger tried a number of gcc tricks to silence this warning, but #pragmas and CPP macros do not work together in the way that would be required to make this work.

This was applied in 2011, and searching LKML during that time gives the following: https://lkml.org/lkml/2011/7/29/305

And in this LKML post, Stephen Hemminger wrote:

Gcc now generates warnings from rcu_assign_pointer when passed the address of something for example:
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
This warning is harmless and should be surpressed but there maybe other cases where we want that Gcc warning.

I tried various combinations of in rcu_assign_pointer macro
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
...
#pragma GCC diagnostic pop
but macro's and pragma's don't nest with the correct scope for this.

Quoted 4 lines

Maybe some one with more Gcc foo and time to waste could take a crack at it.

Adding Stephen on CC in case he remembers more.

So I read all that and am still left wondering WTF the problem was :/

Quoted 7 lines

I googled a bit and found this thread:

https://lkml.org/lkml/2014/3/24/39

Where Michael actually has two 'fixes' to the problem. Instead we continue clutter the API with this silly RCU_INIT_POINTER stuff, totally sad.

Well, there are the other two use cases for RCU_INIT_POINTER().

But yes, most of the actual uses assign NULL.

Quoted 4 lines

But nowhere have I found the actual warning GCC gives, I suppose I can go change my local tree and compile some code to obtain it, but that seems backwards. The patch 'working' around that should have mentioned it and explained why the warning is bogus or not.

Indeed, I should have had a better commit log on the original change.

Thanx, Paul

#7 lore raw

[tip:perf/core] perf/core: Replace rcu_assign_pointer() with RCU_INIT_POINTER()

In reply to Andreea-Cristina Bernat
perf/core: Replace rcu_assign_pointer() with RCU_INIT_POINTER()
Commit-ID:  70691d4a0bf7c871559d4ef1b0056edefbca123b
Gitweb:     http://git.kernel.org/tip/70691d4a0bf7c871559d4ef1b0056edefbca123b
Author:     Andreea-Cristina Bernat <[email protected]>
AuthorDate: Fri, 22 Aug 2014 16:26:05 +0300
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 9 Sep 2014 06:53:05 +0200

perf/core: Replace rcu_assign_pointer() with RCU_INIT_POINTER()

The use of "rcu_assign_pointer()" is NULLing out the pointer. According to RCU_INIT_POINTER()'s block comment:

"1. This use of RCU_INIT_POINTER() is NULLing out the pointer"

it is better to use it instead of rcu_assign_pointer() because it has a smaller overhead.

The following Coccinelle semantic patch was used:
@@
@@

- rcu_assign_pointer
+ RCU_INIT_POINTER

    (..., NULL)
---
 kernel/events/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/events/core.c +1 -1
index 01bd42e..f917dec 100644
@@ -5908,7 +5908,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
 	if (!hlist)
 		return;
 
-	rcu_assign_pointer(swhash->swevent_hlist, NULL);
+	RCU_INIT_POINTER(swhash->swevent_hlist, NULL);
 	kfree_rcu(hlist, rcu_head);
 }