ia64/linux-2.6.18-xen.hg

view drivers/xen/core/cpu_hotplug.c @ 851:67a7ffcc5067

Skip vcpu_hotplug for VCPU 0 in smp_resume.
This function can occasionally take up to 2 seconds to complete,
and smp_suspend also skips VCPU 0.

Signed-off-by: Brendan Cully <brendan@cs.ubc.ca>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 01 11:43:01 2009 +0100 (2009-04-01)
parents bc3e5b96d4f4
children
line source
1 #include <linux/init.h>
2 #include <linux/kernel.h>
3 #include <linux/sched.h>
4 #include <linux/notifier.h>
5 #include <linux/cpu.h>
6 #include <xen/cpu_hotplug.h>
7 #include <xen/xenbus.h>
9 /*
10 * Set of CPUs that remote admin software will allow us to bring online.
11 * Notified to us via xenbus.
12 */
13 static cpumask_t xenbus_allowed_cpumask;
15 /* Set of CPUs that local admin will allow us to bring online. */
16 static cpumask_t local_allowed_cpumask = CPU_MASK_ALL;
18 static int local_cpu_hotplug_request(void)
19 {
20 /*
21 * We assume a CPU hotplug request comes from local admin if it is made
22 * via a userspace process (i.e., one with a real mm_struct).
23 */
24 return (current->mm != NULL);
25 }
27 static void vcpu_hotplug(unsigned int cpu)
28 {
29 int err;
30 char dir[32], state[32];
32 if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
33 return;
35 sprintf(dir, "cpu/%u", cpu);
36 err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
37 if (err != 1) {
38 printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
39 return;
40 }
42 if (strcmp(state, "online") == 0) {
43 cpu_set(cpu, xenbus_allowed_cpumask);
44 (void)cpu_up(cpu);
45 } else if (strcmp(state, "offline") == 0) {
46 cpu_clear(cpu, xenbus_allowed_cpumask);
47 (void)cpu_down(cpu);
48 } else {
49 printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
50 state, cpu);
51 }
52 }
54 static void handle_vcpu_hotplug_event(
55 struct xenbus_watch *watch, const char **vec, unsigned int len)
56 {
57 unsigned int cpu;
58 char *cpustr;
59 const char *node = vec[XS_WATCH_PATH];
61 if ((cpustr = strstr(node, "cpu/")) != NULL) {
62 sscanf(cpustr, "cpu/%u", &cpu);
63 vcpu_hotplug(cpu);
64 }
65 }
67 static int smpboot_cpu_notify(struct notifier_block *notifier,
68 unsigned long action, void *hcpu)
69 {
70 unsigned int cpu = (long)hcpu;
72 /*
73 * We do this in a callback notifier rather than __cpu_disable()
74 * because local_cpu_hotplug_request() does not work in the latter
75 * as it's always executed from within a stopmachine kthread.
76 */
77 if ((action == CPU_DOWN_PREPARE) && local_cpu_hotplug_request())
78 cpu_clear(cpu, local_allowed_cpumask);
80 return NOTIFY_OK;
81 }
83 static int setup_cpu_watcher(struct notifier_block *notifier,
84 unsigned long event, void *data)
85 {
86 unsigned int i;
88 static struct xenbus_watch cpu_watch = {
89 .node = "cpu",
90 .callback = handle_vcpu_hotplug_event,
91 .flags = XBWF_new_thread };
92 (void)register_xenbus_watch(&cpu_watch);
94 if (!is_initial_xendomain()) {
95 for_each_possible_cpu(i)
96 vcpu_hotplug(i);
97 printk(KERN_INFO "Brought up %ld CPUs\n",
98 (long)num_online_cpus());
99 }
101 return NOTIFY_DONE;
102 }
104 static int __init setup_vcpu_hotplug_event(void)
105 {
106 static struct notifier_block hotplug_cpu = {
107 .notifier_call = smpboot_cpu_notify };
108 static struct notifier_block xsn_cpu = {
109 .notifier_call = setup_cpu_watcher };
111 if (!is_running_on_xen())
112 return -ENODEV;
114 register_cpu_notifier(&hotplug_cpu);
115 register_xenstore_notifier(&xsn_cpu);
117 return 0;
118 }
120 arch_initcall(setup_vcpu_hotplug_event);
122 int smp_suspend(void)
123 {
124 unsigned int cpu;
125 int err;
127 for_each_online_cpu(cpu) {
128 if (cpu == 0)
129 continue;
130 err = cpu_down(cpu);
131 if (err) {
132 printk(KERN_CRIT "Failed to take all CPUs "
133 "down: %d.\n", err);
134 for_each_possible_cpu(cpu)
135 vcpu_hotplug(cpu);
136 return err;
137 }
138 }
140 return 0;
141 }
143 void smp_resume(void)
144 {
145 unsigned int cpu;
147 for_each_possible_cpu(cpu) {
148 if (cpu == 0)
149 continue;
150 vcpu_hotplug(cpu);
151 }
152 }
154 int cpu_up_check(unsigned int cpu)
155 {
156 int rc = 0;
158 if (local_cpu_hotplug_request()) {
159 cpu_set(cpu, local_allowed_cpumask);
160 if (!cpu_isset(cpu, xenbus_allowed_cpumask)) {
161 printk("%s: attempt to bring up CPU %u disallowed by "
162 "remote admin.\n", __FUNCTION__, cpu);
163 rc = -EBUSY;
164 }
165 } else if (!cpu_isset(cpu, local_allowed_cpumask) ||
166 !cpu_isset(cpu, xenbus_allowed_cpumask)) {
167 rc = -EBUSY;
168 }
170 return rc;
171 }
173 void init_xenbus_allowed_cpumask(void)
174 {
175 xenbus_allowed_cpumask = cpu_present_map;
176 }