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 |
