diff options
| author | Ingo Molnar <mingo@kernel.org> | 2013-10-18 06:46:14 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2013-10-18 06:46:14 -0400 |
| commit | 0e95c69bde1a5bf22acd53b356fe10d7bec6e2be (patch) | |
| tree | 28c27057fc02a87b5e058b8cb17b2186f86fc95c /include/linux | |
| parent | 04919afb85c8f007b7326c4da5eb61c52e91b9c7 (diff) | |
| parent | 4102adab9189c8ea2f0cdd2f88345fd25d2790f1 (diff) | |
Merge branch 'rcu/next' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into core/rcu
Pull RCU updates from Paul E. McKenney.
Major changes:
" 1. Update RCU documentation. These were posted to LKML at
http://article.gmane.org/gmane.linux.kernel/1566994.
2. Miscellaneous fixes. These were posted to LKML at
http://article.gmane.org/gmane.linux.kernel/1567027.
3. Grace-period-related changes, primarily to aid in debugging,
inspired by a -rt debugging session. These were posted to
LKML at http://article.gmane.org/gmane.linux.kernel/1567076.
4. Idle entry/exit changes, primarily to address issues located
by Tibor Billes. These were posted to LKML at
http://article.gmane.org/gmane.linux.kernel/1567096.
5. Code reorganization moving RCU's source files from kernel
to kernel/rcu. This was posted to LKML at
http://article.gmane.org/gmane.linux.kernel/1577344."
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/rculist.h | 23 | ||||
| -rw-r--r-- | include/linux/rcupdate.h | 24 | ||||
| -rw-r--r-- | include/linux/rcutiny.h | 17 | ||||
| -rw-r--r-- | include/linux/rcutree.h | 2 |
4 files changed, 52 insertions, 14 deletions
diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 4106721c4e5e..45a0a9e81478 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h | |||
| @@ -19,6 +19,21 @@ | |||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * INIT_LIST_HEAD_RCU - Initialize a list_head visible to RCU readers | ||
| 23 | * @list: list to be initialized | ||
| 24 | * | ||
| 25 | * You should instead use INIT_LIST_HEAD() for normal initialization and | ||
| 26 | * cleanup tasks, when readers have no access to the list being initialized. | ||
| 27 | * However, if the list being initialized is visible to readers, you | ||
| 28 | * need to keep the compiler from being too mischievous. | ||
| 29 | */ | ||
| 30 | static inline void INIT_LIST_HEAD_RCU(struct list_head *list) | ||
| 31 | { | ||
| 32 | ACCESS_ONCE(list->next) = list; | ||
| 33 | ACCESS_ONCE(list->prev) = list; | ||
| 34 | } | ||
| 35 | |||
| 36 | /* | ||
| 22 | * return the ->next pointer of a list_head in an rcu safe | 37 | * return the ->next pointer of a list_head in an rcu safe |
| 23 | * way, we must not access it directly | 38 | * way, we must not access it directly |
| 24 | */ | 39 | */ |
| @@ -191,9 +206,13 @@ static inline void list_splice_init_rcu(struct list_head *list, | |||
| 191 | if (list_empty(list)) | 206 | if (list_empty(list)) |
| 192 | return; | 207 | return; |
| 193 | 208 | ||
| 194 | /* "first" and "last" tracking list, so initialize it. */ | 209 | /* |
| 210 | * "first" and "last" tracking list, so initialize it. RCU readers | ||
| 211 | * have access to this list, so we must use INIT_LIST_HEAD_RCU() | ||
| 212 | * instead of INIT_LIST_HEAD(). | ||
| 213 | */ | ||
| 195 | 214 | ||
| 196 | INIT_LIST_HEAD(list); | 215 | INIT_LIST_HEAD_RCU(list); |
| 197 | 216 | ||
| 198 | /* | 217 | /* |
| 199 | * At this point, the list body still points to the source list. | 218 | * At this point, the list body still points to the source list. |
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index f1f1bc39346b..39cbb889e20d 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
| @@ -261,6 +261,10 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev, | |||
| 261 | rcu_irq_exit(); \ | 261 | rcu_irq_exit(); \ |
| 262 | } while (0) | 262 | } while (0) |
| 263 | 263 | ||
| 264 | #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) | ||
| 265 | extern bool __rcu_is_watching(void); | ||
| 266 | #endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */ | ||
| 267 | |||
| 264 | /* | 268 | /* |
| 265 | * Infrastructure to implement the synchronize_() primitives in | 269 | * Infrastructure to implement the synchronize_() primitives in |
| 266 | * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. | 270 | * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. |
| @@ -297,10 +301,6 @@ static inline void destroy_rcu_head_on_stack(struct rcu_head *head) | |||
| 297 | } | 301 | } |
| 298 | #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ | 302 | #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ |
| 299 | 303 | ||
| 300 | #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP) | ||
| 301 | extern int rcu_is_cpu_idle(void); | ||
| 302 | #endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP) */ | ||
| 303 | |||
| 304 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) | 304 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) |
| 305 | bool rcu_lockdep_current_cpu_online(void); | 305 | bool rcu_lockdep_current_cpu_online(void); |
| 306 | #else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ | 306 | #else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ |
| @@ -351,7 +351,7 @@ static inline int rcu_read_lock_held(void) | |||
| 351 | { | 351 | { |
| 352 | if (!debug_lockdep_rcu_enabled()) | 352 | if (!debug_lockdep_rcu_enabled()) |
| 353 | return 1; | 353 | return 1; |
| 354 | if (rcu_is_cpu_idle()) | 354 | if (!rcu_is_watching()) |
| 355 | return 0; | 355 | return 0; |
| 356 | if (!rcu_lockdep_current_cpu_online()) | 356 | if (!rcu_lockdep_current_cpu_online()) |
| 357 | return 0; | 357 | return 0; |
| @@ -402,7 +402,7 @@ static inline int rcu_read_lock_sched_held(void) | |||
| 402 | 402 | ||
| 403 | if (!debug_lockdep_rcu_enabled()) | 403 | if (!debug_lockdep_rcu_enabled()) |
| 404 | return 1; | 404 | return 1; |
| 405 | if (rcu_is_cpu_idle()) | 405 | if (!rcu_is_watching()) |
| 406 | return 0; | 406 | return 0; |
| 407 | if (!rcu_lockdep_current_cpu_online()) | 407 | if (!rcu_lockdep_current_cpu_online()) |
| 408 | return 0; | 408 | return 0; |
| @@ -771,7 +771,7 @@ static inline void rcu_read_lock(void) | |||
| 771 | __rcu_read_lock(); | 771 | __rcu_read_lock(); |
| 772 | __acquire(RCU); | 772 | __acquire(RCU); |
| 773 | rcu_lock_acquire(&rcu_lock_map); | 773 | rcu_lock_acquire(&rcu_lock_map); |
| 774 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | 774 | rcu_lockdep_assert(rcu_is_watching(), |
| 775 | "rcu_read_lock() used illegally while idle"); | 775 | "rcu_read_lock() used illegally while idle"); |
| 776 | } | 776 | } |
| 777 | 777 | ||
| @@ -792,7 +792,7 @@ static inline void rcu_read_lock(void) | |||
| 792 | */ | 792 | */ |
| 793 | static inline void rcu_read_unlock(void) | 793 | static inline void rcu_read_unlock(void) |
| 794 | { | 794 | { |
| 795 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | 795 | rcu_lockdep_assert(rcu_is_watching(), |
| 796 | "rcu_read_unlock() used illegally while idle"); | 796 | "rcu_read_unlock() used illegally while idle"); |
| 797 | rcu_lock_release(&rcu_lock_map); | 797 | rcu_lock_release(&rcu_lock_map); |
| 798 | __release(RCU); | 798 | __release(RCU); |
| @@ -821,7 +821,7 @@ static inline void rcu_read_lock_bh(void) | |||
| 821 | local_bh_disable(); | 821 | local_bh_disable(); |
| 822 | __acquire(RCU_BH); | 822 | __acquire(RCU_BH); |
| 823 | rcu_lock_acquire(&rcu_bh_lock_map); | 823 | rcu_lock_acquire(&rcu_bh_lock_map); |
| 824 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | 824 | rcu_lockdep_assert(rcu_is_watching(), |
| 825 | "rcu_read_lock_bh() used illegally while idle"); | 825 | "rcu_read_lock_bh() used illegally while idle"); |
| 826 | } | 826 | } |
| 827 | 827 | ||
| @@ -832,7 +832,7 @@ static inline void rcu_read_lock_bh(void) | |||
| 832 | */ | 832 | */ |
| 833 | static inline void rcu_read_unlock_bh(void) | 833 | static inline void rcu_read_unlock_bh(void) |
| 834 | { | 834 | { |
| 835 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | 835 | rcu_lockdep_assert(rcu_is_watching(), |
| 836 | "rcu_read_unlock_bh() used illegally while idle"); | 836 | "rcu_read_unlock_bh() used illegally while idle"); |
| 837 | rcu_lock_release(&rcu_bh_lock_map); | 837 | rcu_lock_release(&rcu_bh_lock_map); |
| 838 | __release(RCU_BH); | 838 | __release(RCU_BH); |
| @@ -857,7 +857,7 @@ static inline void rcu_read_lock_sched(void) | |||
| 857 | preempt_disable(); | 857 | preempt_disable(); |
| 858 | __acquire(RCU_SCHED); | 858 | __acquire(RCU_SCHED); |
| 859 | rcu_lock_acquire(&rcu_sched_lock_map); | 859 | rcu_lock_acquire(&rcu_sched_lock_map); |
| 860 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | 860 | rcu_lockdep_assert(rcu_is_watching(), |
| 861 | "rcu_read_lock_sched() used illegally while idle"); | 861 | "rcu_read_lock_sched() used illegally while idle"); |
| 862 | } | 862 | } |
| 863 | 863 | ||
| @@ -875,7 +875,7 @@ static inline notrace void rcu_read_lock_sched_notrace(void) | |||
| 875 | */ | 875 | */ |
| 876 | static inline void rcu_read_unlock_sched(void) | 876 | static inline void rcu_read_unlock_sched(void) |
| 877 | { | 877 | { |
| 878 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | 878 | rcu_lockdep_assert(rcu_is_watching(), |
| 879 | "rcu_read_unlock_sched() used illegally while idle"); | 879 | "rcu_read_unlock_sched() used illegally while idle"); |
| 880 | rcu_lock_release(&rcu_sched_lock_map); | 880 | rcu_lock_release(&rcu_sched_lock_map); |
| 881 | __release(RCU_SCHED); | 881 | __release(RCU_SCHED); |
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index e31005ee339e..09ebcbe9fd78 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h | |||
| @@ -132,4 +132,21 @@ static inline void rcu_scheduler_starting(void) | |||
| 132 | } | 132 | } |
| 133 | #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ | 133 | #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
| 134 | 134 | ||
| 135 | #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) | ||
| 136 | |||
| 137 | static inline bool rcu_is_watching(void) | ||
| 138 | { | ||
| 139 | return __rcu_is_watching(); | ||
| 140 | } | ||
| 141 | |||
| 142 | #else /* defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ | ||
| 143 | |||
| 144 | static inline bool rcu_is_watching(void) | ||
| 145 | { | ||
| 146 | return true; | ||
| 147 | } | ||
| 148 | |||
| 149 | |||
| 150 | #endif /* #else defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ | ||
| 151 | |||
| 135 | #endif /* __LINUX_RCUTINY_H */ | 152 | #endif /* __LINUX_RCUTINY_H */ |
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 226169d1bd2b..4b9c81548742 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h | |||
| @@ -90,4 +90,6 @@ extern void exit_rcu(void); | |||
| 90 | extern void rcu_scheduler_starting(void); | 90 | extern void rcu_scheduler_starting(void); |
| 91 | extern int rcu_scheduler_active __read_mostly; | 91 | extern int rcu_scheduler_active __read_mostly; |
| 92 | 92 | ||
| 93 | extern bool rcu_is_watching(void); | ||
| 94 | |||
| 93 | #endif /* __LINUX_RCUTREE_H */ | 95 | #endif /* __LINUX_RCUTREE_H */ |
