diff options
Diffstat (limited to 'kernel/cpu.c')
-rw-r--r-- | kernel/cpu.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 3619e939182e..d61ba88f34e5 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -21,6 +21,24 @@ EXPORT_SYMBOL_GPL(cpucontrol); | |||
21 | 21 | ||
22 | static struct notifier_block *cpu_chain; | 22 | static struct notifier_block *cpu_chain; |
23 | 23 | ||
24 | /* | ||
25 | * Used to check by callers if they need to acquire the cpucontrol | ||
26 | * or not to protect a cpu from being removed. Its sometimes required to | ||
27 | * call these functions both for normal operations, and in response to | ||
28 | * a cpu being added/removed. If the context of the call is in the same | ||
29 | * thread context as a CPU hotplug thread, we dont need to take the lock | ||
30 | * since its already protected | ||
31 | * check drivers/cpufreq/cpufreq.c for its usage - Ashok Raj | ||
32 | */ | ||
33 | |||
34 | int current_in_cpu_hotplug(void) | ||
35 | { | ||
36 | return (current->flags & PF_HOTPLUG_CPU); | ||
37 | } | ||
38 | |||
39 | EXPORT_SYMBOL_GPL(current_in_cpu_hotplug); | ||
40 | |||
41 | |||
24 | /* Need to know about CPUs going up/down? */ | 42 | /* Need to know about CPUs going up/down? */ |
25 | int register_cpu_notifier(struct notifier_block *nb) | 43 | int register_cpu_notifier(struct notifier_block *nb) |
26 | { | 44 | { |
@@ -94,6 +112,13 @@ int cpu_down(unsigned int cpu) | |||
94 | goto out; | 112 | goto out; |
95 | } | 113 | } |
96 | 114 | ||
115 | /* | ||
116 | * Leave a trace in current->flags indicating we are already in | ||
117 | * process of performing CPU hotplug. Callers can check if cpucontrol | ||
118 | * is already acquired by current thread, and if so not cause | ||
119 | * a dead lock by not acquiring the lock | ||
120 | */ | ||
121 | current->flags |= PF_HOTPLUG_CPU; | ||
97 | err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, | 122 | err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, |
98 | (void *)(long)cpu); | 123 | (void *)(long)cpu); |
99 | if (err == NOTIFY_BAD) { | 124 | if (err == NOTIFY_BAD) { |
@@ -146,6 +171,7 @@ out_thread: | |||
146 | out_allowed: | 171 | out_allowed: |
147 | set_cpus_allowed(current, old_allowed); | 172 | set_cpus_allowed(current, old_allowed); |
148 | out: | 173 | out: |
174 | current->flags &= ~PF_HOTPLUG_CPU; | ||
149 | unlock_cpu_hotplug(); | 175 | unlock_cpu_hotplug(); |
150 | return err; | 176 | return err; |
151 | } | 177 | } |
@@ -163,6 +189,12 @@ int __devinit cpu_up(unsigned int cpu) | |||
163 | ret = -EINVAL; | 189 | ret = -EINVAL; |
164 | goto out; | 190 | goto out; |
165 | } | 191 | } |
192 | |||
193 | /* | ||
194 | * Leave a trace in current->flags indicating we are already in | ||
195 | * process of performing CPU hotplug. | ||
196 | */ | ||
197 | current->flags |= PF_HOTPLUG_CPU; | ||
166 | ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); | 198 | ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); |
167 | if (ret == NOTIFY_BAD) { | 199 | if (ret == NOTIFY_BAD) { |
168 | printk("%s: attempt to bring up CPU %u failed\n", | 200 | printk("%s: attempt to bring up CPU %u failed\n", |
@@ -185,6 +217,7 @@ out_notify: | |||
185 | if (ret != 0) | 217 | if (ret != 0) |
186 | notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); | 218 | notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); |
187 | out: | 219 | out: |
220 | current->flags &= ~PF_HOTPLUG_CPU; | ||
188 | up(&cpucontrol); | 221 | up(&cpucontrol); |
189 | return ret; | 222 | return ret; |
190 | } | 223 | } |