diff options
-rw-r--r-- | include/linux/cpu.h | 2 | ||||
-rw-r--r-- | include/linux/lockdep.h | 1 | ||||
-rw-r--r-- | kernel/cpu.c | 16 | ||||
-rw-r--r-- | kernel/rcu/tree.c | 19 | ||||
-rw-r--r-- | kernel/rcu/tree_plugin.h | 11 |
5 files changed, 35 insertions, 14 deletions
diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 95978ad7fcdd..b2d9a43012b2 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h | |||
@@ -213,6 +213,7 @@ extern struct bus_type cpu_subsys; | |||
213 | extern void cpu_hotplug_begin(void); | 213 | extern void cpu_hotplug_begin(void); |
214 | extern void cpu_hotplug_done(void); | 214 | extern void cpu_hotplug_done(void); |
215 | extern void get_online_cpus(void); | 215 | extern void get_online_cpus(void); |
216 | extern bool try_get_online_cpus(void); | ||
216 | extern void put_online_cpus(void); | 217 | extern void put_online_cpus(void); |
217 | extern void cpu_hotplug_disable(void); | 218 | extern void cpu_hotplug_disable(void); |
218 | extern void cpu_hotplug_enable(void); | 219 | extern void cpu_hotplug_enable(void); |
@@ -230,6 +231,7 @@ int cpu_down(unsigned int cpu); | |||
230 | static inline void cpu_hotplug_begin(void) {} | 231 | static inline void cpu_hotplug_begin(void) {} |
231 | static inline void cpu_hotplug_done(void) {} | 232 | static inline void cpu_hotplug_done(void) {} |
232 | #define get_online_cpus() do { } while (0) | 233 | #define get_online_cpus() do { } while (0) |
234 | #define try_get_online_cpus() true | ||
233 | #define put_online_cpus() do { } while (0) | 235 | #define put_online_cpus() do { } while (0) |
234 | #define cpu_hotplug_disable() do { } while (0) | 236 | #define cpu_hotplug_disable() do { } while (0) |
235 | #define cpu_hotplug_enable() do { } while (0) | 237 | #define cpu_hotplug_enable() do { } while (0) |
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 008388f920d7..4f86465cc317 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -505,6 +505,7 @@ static inline void print_irqtrace_events(struct task_struct *curr) | |||
505 | 505 | ||
506 | #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) | 506 | #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) |
507 | #define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) | 507 | #define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) |
508 | #define lock_map_acquire_tryread(l) lock_acquire_shared_recursive(l, 0, 1, NULL, _THIS_IP_) | ||
508 | #define lock_map_release(l) lock_release(l, 1, _THIS_IP_) | 509 | #define lock_map_release(l) lock_release(l, 1, _THIS_IP_) |
509 | 510 | ||
510 | #ifdef CONFIG_PROVE_LOCKING | 511 | #ifdef CONFIG_PROVE_LOCKING |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 81e2a388a0f6..356450f09c1f 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -79,6 +79,8 @@ static struct { | |||
79 | 79 | ||
80 | /* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */ | 80 | /* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */ |
81 | #define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map) | 81 | #define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map) |
82 | #define cpuhp_lock_acquire_tryread() \ | ||
83 | lock_map_acquire_tryread(&cpu_hotplug.dep_map) | ||
82 | #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) | 84 | #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) |
83 | #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) | 85 | #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) |
84 | 86 | ||
@@ -91,10 +93,22 @@ void get_online_cpus(void) | |||
91 | mutex_lock(&cpu_hotplug.lock); | 93 | mutex_lock(&cpu_hotplug.lock); |
92 | cpu_hotplug.refcount++; | 94 | cpu_hotplug.refcount++; |
93 | mutex_unlock(&cpu_hotplug.lock); | 95 | mutex_unlock(&cpu_hotplug.lock); |
94 | |||
95 | } | 96 | } |
96 | EXPORT_SYMBOL_GPL(get_online_cpus); | 97 | EXPORT_SYMBOL_GPL(get_online_cpus); |
97 | 98 | ||
99 | bool try_get_online_cpus(void) | ||
100 | { | ||
101 | if (cpu_hotplug.active_writer == current) | ||
102 | return true; | ||
103 | if (!mutex_trylock(&cpu_hotplug.lock)) | ||
104 | return false; | ||
105 | cpuhp_lock_acquire_tryread(); | ||
106 | cpu_hotplug.refcount++; | ||
107 | mutex_unlock(&cpu_hotplug.lock); | ||
108 | return true; | ||
109 | } | ||
110 | EXPORT_SYMBOL_GPL(try_get_online_cpus); | ||
111 | |||
98 | void put_online_cpus(void) | 112 | void put_online_cpus(void) |
99 | { | 113 | { |
100 | if (cpu_hotplug.active_writer == current) | 114 | if (cpu_hotplug.active_writer == current) |
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index d7a3b13bc94c..133e47223095 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -2940,11 +2940,6 @@ static int synchronize_sched_expedited_cpu_stop(void *data) | |||
2940 | * restructure your code to batch your updates, and then use a single | 2940 | * restructure your code to batch your updates, and then use a single |
2941 | * synchronize_sched() instead. | 2941 | * synchronize_sched() instead. |
2942 | * | 2942 | * |
2943 | * Note that it is illegal to call this function while holding any lock | ||
2944 | * that is acquired by a CPU-hotplug notifier. And yes, it is also illegal | ||
2945 | * to call this function from a CPU-hotplug notifier. Failing to observe | ||
2946 | * these restriction will result in deadlock. | ||
2947 | * | ||
2948 | * This implementation can be thought of as an application of ticket | 2943 | * This implementation can be thought of as an application of ticket |
2949 | * locking to RCU, with sync_sched_expedited_started and | 2944 | * locking to RCU, with sync_sched_expedited_started and |
2950 | * sync_sched_expedited_done taking on the roles of the halves | 2945 | * sync_sched_expedited_done taking on the roles of the halves |
@@ -2994,7 +2989,12 @@ void synchronize_sched_expedited(void) | |||
2994 | */ | 2989 | */ |
2995 | snap = atomic_long_inc_return(&rsp->expedited_start); | 2990 | snap = atomic_long_inc_return(&rsp->expedited_start); |
2996 | firstsnap = snap; | 2991 | firstsnap = snap; |
2997 | get_online_cpus(); | 2992 | if (!try_get_online_cpus()) { |
2993 | /* CPU hotplug operation in flight, fall back to normal GP. */ | ||
2994 | wait_rcu_gp(call_rcu_sched); | ||
2995 | atomic_long_inc(&rsp->expedited_normal); | ||
2996 | return; | ||
2997 | } | ||
2998 | WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id())); | 2998 | WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id())); |
2999 | 2999 | ||
3000 | /* | 3000 | /* |
@@ -3041,7 +3041,12 @@ void synchronize_sched_expedited(void) | |||
3041 | * and they started after our first try, so their grace | 3041 | * and they started after our first try, so their grace |
3042 | * period works for us. | 3042 | * period works for us. |
3043 | */ | 3043 | */ |
3044 | get_online_cpus(); | 3044 | if (!try_get_online_cpus()) { |
3045 | /* CPU hotplug operation in flight, use normal GP. */ | ||
3046 | wait_rcu_gp(call_rcu_sched); | ||
3047 | atomic_long_inc(&rsp->expedited_normal); | ||
3048 | return; | ||
3049 | } | ||
3045 | snap = atomic_long_read(&rsp->expedited_start); | 3050 | snap = atomic_long_read(&rsp->expedited_start); |
3046 | smp_mb(); /* ensure read is before try_stop_cpus(). */ | 3051 | smp_mb(); /* ensure read is before try_stop_cpus(). */ |
3047 | } | 3052 | } |
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index e2c5910546f6..387dd4599344 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h | |||
@@ -793,11 +793,6 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) | |||
793 | * In fact, if you are using synchronize_rcu_expedited() in a loop, | 793 | * In fact, if you are using synchronize_rcu_expedited() in a loop, |
794 | * please restructure your code to batch your updates, and then Use a | 794 | * please restructure your code to batch your updates, and then Use a |
795 | * single synchronize_rcu() instead. | 795 | * single synchronize_rcu() instead. |
796 | * | ||
797 | * Note that it is illegal to call this function while holding any lock | ||
798 | * that is acquired by a CPU-hotplug notifier. And yes, it is also illegal | ||
799 | * to call this function from a CPU-hotplug notifier. Failing to observe | ||
800 | * these restriction will result in deadlock. | ||
801 | */ | 796 | */ |
802 | void synchronize_rcu_expedited(void) | 797 | void synchronize_rcu_expedited(void) |
803 | { | 798 | { |
@@ -819,7 +814,11 @@ void synchronize_rcu_expedited(void) | |||
819 | * being boosted. This simplifies the process of moving tasks | 814 | * being boosted. This simplifies the process of moving tasks |
820 | * from leaf to root rcu_node structures. | 815 | * from leaf to root rcu_node structures. |
821 | */ | 816 | */ |
822 | get_online_cpus(); | 817 | if (!try_get_online_cpus()) { |
818 | /* CPU-hotplug operation in flight, fall back to normal GP. */ | ||
819 | wait_rcu_gp(call_rcu); | ||
820 | return; | ||
821 | } | ||
823 | 822 | ||
824 | /* | 823 | /* |
825 | * Acquire lock, falling back to synchronize_rcu() if too many | 824 | * Acquire lock, falling back to synchronize_rcu() if too many |