diff options
Diffstat (limited to 'kernel/cpu.c')
| -rw-r--r-- | kernel/cpu.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 356450f09c1f..90a3d017b90c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -64,6 +64,8 @@ static struct { | |||
| 64 | * an ongoing cpu hotplug operation. | 64 | * an ongoing cpu hotplug operation. |
| 65 | */ | 65 | */ |
| 66 | int refcount; | 66 | int refcount; |
| 67 | /* And allows lockless put_online_cpus(). */ | ||
| 68 | atomic_t puts_pending; | ||
| 67 | 69 | ||
| 68 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 70 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
| 69 | struct lockdep_map dep_map; | 71 | struct lockdep_map dep_map; |
| @@ -113,7 +115,11 @@ void put_online_cpus(void) | |||
| 113 | { | 115 | { |
| 114 | if (cpu_hotplug.active_writer == current) | 116 | if (cpu_hotplug.active_writer == current) |
| 115 | return; | 117 | return; |
| 116 | mutex_lock(&cpu_hotplug.lock); | 118 | if (!mutex_trylock(&cpu_hotplug.lock)) { |
| 119 | atomic_inc(&cpu_hotplug.puts_pending); | ||
| 120 | cpuhp_lock_release(); | ||
| 121 | return; | ||
| 122 | } | ||
| 117 | 123 | ||
| 118 | if (WARN_ON(!cpu_hotplug.refcount)) | 124 | if (WARN_ON(!cpu_hotplug.refcount)) |
| 119 | cpu_hotplug.refcount++; /* try to fix things up */ | 125 | cpu_hotplug.refcount++; /* try to fix things up */ |
| @@ -155,6 +161,12 @@ void cpu_hotplug_begin(void) | |||
| 155 | cpuhp_lock_acquire(); | 161 | cpuhp_lock_acquire(); |
| 156 | for (;;) { | 162 | for (;;) { |
| 157 | mutex_lock(&cpu_hotplug.lock); | 163 | mutex_lock(&cpu_hotplug.lock); |
| 164 | if (atomic_read(&cpu_hotplug.puts_pending)) { | ||
| 165 | int delta; | ||
| 166 | |||
| 167 | delta = atomic_xchg(&cpu_hotplug.puts_pending, 0); | ||
| 168 | cpu_hotplug.refcount -= delta; | ||
| 169 | } | ||
| 158 | if (likely(!cpu_hotplug.refcount)) | 170 | if (likely(!cpu_hotplug.refcount)) |
| 159 | break; | 171 | break; |
| 160 | __set_current_state(TASK_UNINTERRUPTIBLE); | 172 | __set_current_state(TASK_UNINTERRUPTIBLE); |
