diff options
Diffstat (limited to 'kernel/cpu.c')
-rw-r--r-- | kernel/cpu.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 356450f09c1f..5d220234b3ca 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; |
@@ -84,6 +86,16 @@ static struct { | |||
84 | #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) | 86 | #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) |
85 | #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) | 87 | #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) |
86 | 88 | ||
89 | static void apply_puts_pending(int max) | ||
90 | { | ||
91 | int delta; | ||
92 | |||
93 | if (atomic_read(&cpu_hotplug.puts_pending) >= max) { | ||
94 | delta = atomic_xchg(&cpu_hotplug.puts_pending, 0); | ||
95 | cpu_hotplug.refcount -= delta; | ||
96 | } | ||
97 | } | ||
98 | |||
87 | void get_online_cpus(void) | 99 | void get_online_cpus(void) |
88 | { | 100 | { |
89 | might_sleep(); | 101 | might_sleep(); |
@@ -91,6 +103,7 @@ void get_online_cpus(void) | |||
91 | return; | 103 | return; |
92 | cpuhp_lock_acquire_read(); | 104 | cpuhp_lock_acquire_read(); |
93 | mutex_lock(&cpu_hotplug.lock); | 105 | mutex_lock(&cpu_hotplug.lock); |
106 | apply_puts_pending(65536); | ||
94 | cpu_hotplug.refcount++; | 107 | cpu_hotplug.refcount++; |
95 | mutex_unlock(&cpu_hotplug.lock); | 108 | mutex_unlock(&cpu_hotplug.lock); |
96 | } | 109 | } |
@@ -103,6 +116,7 @@ bool try_get_online_cpus(void) | |||
103 | if (!mutex_trylock(&cpu_hotplug.lock)) | 116 | if (!mutex_trylock(&cpu_hotplug.lock)) |
104 | return false; | 117 | return false; |
105 | cpuhp_lock_acquire_tryread(); | 118 | cpuhp_lock_acquire_tryread(); |
119 | apply_puts_pending(65536); | ||
106 | cpu_hotplug.refcount++; | 120 | cpu_hotplug.refcount++; |
107 | mutex_unlock(&cpu_hotplug.lock); | 121 | mutex_unlock(&cpu_hotplug.lock); |
108 | return true; | 122 | return true; |
@@ -113,7 +127,11 @@ void put_online_cpus(void) | |||
113 | { | 127 | { |
114 | if (cpu_hotplug.active_writer == current) | 128 | if (cpu_hotplug.active_writer == current) |
115 | return; | 129 | return; |
116 | mutex_lock(&cpu_hotplug.lock); | 130 | if (!mutex_trylock(&cpu_hotplug.lock)) { |
131 | atomic_inc(&cpu_hotplug.puts_pending); | ||
132 | cpuhp_lock_release(); | ||
133 | return; | ||
134 | } | ||
117 | 135 | ||
118 | if (WARN_ON(!cpu_hotplug.refcount)) | 136 | if (WARN_ON(!cpu_hotplug.refcount)) |
119 | cpu_hotplug.refcount++; /* try to fix things up */ | 137 | cpu_hotplug.refcount++; /* try to fix things up */ |
@@ -155,6 +173,7 @@ void cpu_hotplug_begin(void) | |||
155 | cpuhp_lock_acquire(); | 173 | cpuhp_lock_acquire(); |
156 | for (;;) { | 174 | for (;;) { |
157 | mutex_lock(&cpu_hotplug.lock); | 175 | mutex_lock(&cpu_hotplug.lock); |
176 | apply_puts_pending(1); | ||
158 | if (likely(!cpu_hotplug.refcount)) | 177 | if (likely(!cpu_hotplug.refcount)) |
159 | break; | 178 | break; |
160 | __set_current_state(TASK_UNINTERRUPTIBLE); | 179 | __set_current_state(TASK_UNINTERRUPTIBLE); |