Commit ff195cb69ba8d2af9b891be3a26db95fe1999d43
Committed by
Paul E. McKenney
1 parent
d8ab29f8be
Exists in
master
and in
6 other branches
rcu: Warn when srcu_read_lock() is used in an extended quiescent state
Catch SRCU up to the other variants of RCU by making PROVE_RCU complain if either srcu_read_lock() or srcu_read_lock_held() are used from within RCU-idle mode. Frederic reworked this to allow for the new versions of his patches that check for extended quiescent states. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Showing 1 changed file with 23 additions and 13 deletions Side-by-side Diff
include/linux/srcu.h
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | #define _LINUX_SRCU_H |
29 | 29 | |
30 | 30 | #include <linux/mutex.h> |
31 | +#include <linux/rcupdate.h> | |
31 | 32 | |
32 | 33 | struct srcu_struct_array { |
33 | 34 | int c[2]; |
34 | 35 | |
... | ... | @@ -60,18 +61,10 @@ |
60 | 61 | __init_srcu_struct((sp), #sp, &__srcu_key); \ |
61 | 62 | }) |
62 | 63 | |
63 | -# define srcu_read_acquire(sp) \ | |
64 | - lock_acquire(&(sp)->dep_map, 0, 0, 2, 1, NULL, _THIS_IP_) | |
65 | -# define srcu_read_release(sp) \ | |
66 | - lock_release(&(sp)->dep_map, 1, _THIS_IP_) | |
67 | - | |
68 | 64 | #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
69 | 65 | |
70 | 66 | int init_srcu_struct(struct srcu_struct *sp); |
71 | 67 | |
72 | -# define srcu_read_acquire(sp) do { } while (0) | |
73 | -# define srcu_read_release(sp) do { } while (0) | |
74 | - | |
75 | 68 | #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
76 | 69 | |
77 | 70 | void cleanup_srcu_struct(struct srcu_struct *sp); |
78 | 71 | |
... | ... | @@ -90,12 +83,29 @@ |
90 | 83 | * read-side critical section. In absence of CONFIG_DEBUG_LOCK_ALLOC, |
91 | 84 | * this assumes we are in an SRCU read-side critical section unless it can |
92 | 85 | * prove otherwise. |
86 | + * | |
87 | + * Note that if the CPU is in the idle loop from an RCU point of view | |
88 | + * (ie: that we are in the section between rcu_idle_enter() and | |
89 | + * rcu_idle_exit()) then srcu_read_lock_held() returns false even if | |
90 | + * the CPU did an srcu_read_lock(). The reason for this is that RCU | |
91 | + * ignores CPUs that are in such a section, considering these as in | |
92 | + * extended quiescent state, so such a CPU is effectively never in an | |
93 | + * RCU read-side critical section regardless of what RCU primitives it | |
94 | + * invokes. This state of affairs is required --- we need to keep an | |
95 | + * RCU-free window in idle where the CPU may possibly enter into low | |
96 | + * power mode. This way we can notice an extended quiescent state to | |
97 | + * other CPUs that started a grace period. Otherwise we would delay any | |
98 | + * grace period as long as we run in the idle task. | |
93 | 99 | */ |
94 | 100 | static inline int srcu_read_lock_held(struct srcu_struct *sp) |
95 | 101 | { |
96 | - if (debug_locks) | |
97 | - return lock_is_held(&sp->dep_map); | |
98 | - return 1; | |
102 | + if (rcu_is_cpu_idle()) | |
103 | + return 0; | |
104 | + | |
105 | + if (!debug_locks) | |
106 | + return 1; | |
107 | + | |
108 | + return lock_is_held(&sp->dep_map); | |
99 | 109 | } |
100 | 110 | |
101 | 111 | #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
... | ... | @@ -150,7 +160,7 @@ |
150 | 160 | { |
151 | 161 | int retval = __srcu_read_lock(sp); |
152 | 162 | |
153 | - srcu_read_acquire(sp); | |
163 | + rcu_lock_acquire(&(sp)->dep_map); | |
154 | 164 | return retval; |
155 | 165 | } |
156 | 166 | |
... | ... | @@ -164,7 +174,7 @@ |
164 | 174 | static inline void srcu_read_unlock(struct srcu_struct *sp, int idx) |
165 | 175 | __releases(sp) |
166 | 176 | { |
167 | - srcu_read_release(sp); | |
177 | + rcu_lock_release(&(sp)->dep_map); | |
168 | 178 | __srcu_read_unlock(sp, idx); |
169 | 179 | } |
170 | 180 |