direct-io.hg

view linux-2.6-xen-sparse/drivers/xen/core/cpu_hotplug.c @ 10472:fc1c6dfd1807

[LINUX] Transparent virtualization fixes.
Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author kaf24@firebug.cl.cam.ac.uk
date Wed Jun 21 16:54:09 2006 +0100 (2006-06-21)
parents 49f65e2b0f1c
children d8338b28bcd6
line source
1 #include <linux/config.h>
2 #include <linux/init.h>
3 #include <linux/kernel.h>
4 #include <linux/sched.h>
5 #include <linux/notifier.h>
6 #include <linux/cpu.h>
7 #include <xen/cpu_hotplug.h>
8 #include <xen/xenbus.h>
10 /*
11 * Set of CPUs that remote admin software will allow us to bring online.
12 * Notified to us via xenbus.
13 */
14 static cpumask_t xenbus_allowed_cpumask;
16 /* Set of CPUs that local admin will allow us to bring online. */
17 static cpumask_t local_allowed_cpumask = CPU_MASK_ALL;
19 static int local_cpu_hotplug_request(void)
20 {
21 /*
22 * We assume a CPU hotplug request comes from local admin if it is made
23 * via a userspace process (i.e., one with a real mm_struct).
24 */
25 return (current->mm != NULL);
26 }
28 static void vcpu_hotplug(unsigned int cpu)
29 {
30 int err;
31 char dir[32], state[32];
33 if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
34 return;
36 sprintf(dir, "cpu/%d", cpu);
37 err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
38 if (err != 1) {
39 printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
40 return;
41 }
43 if (strcmp(state, "online") == 0) {
44 cpu_set(cpu, xenbus_allowed_cpumask);
45 (void)cpu_up(cpu);
46 } else if (strcmp(state, "offline") == 0) {
47 cpu_clear(cpu, xenbus_allowed_cpumask);
48 (void)cpu_down(cpu);
49 } else {
50 printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
51 state, cpu);
52 }
53 }
55 static void handle_vcpu_hotplug_event(
56 struct xenbus_watch *watch, const char **vec, unsigned int len)
57 {
58 int cpu;
59 char *cpustr;
60 const char *node = vec[XS_WATCH_PATH];
62 if ((cpustr = strstr(node, "cpu/")) != NULL) {
63 sscanf(cpustr, "cpu/%d", &cpu);
64 vcpu_hotplug(cpu);
65 }
66 }
68 static int smpboot_cpu_notify(struct notifier_block *notifier,
69 unsigned long action, void *hcpu)
70 {
71 int cpu = (long)hcpu;
73 /*
74 * We do this in a callback notifier rather than __cpu_disable()
75 * because local_cpu_hotplug_request() does not work in the latter
76 * as it's always executed from within a stopmachine kthread.
77 */
78 if ((action == CPU_DOWN_PREPARE) && local_cpu_hotplug_request())
79 cpu_clear(cpu, local_allowed_cpumask);
81 return NOTIFY_OK;
82 }
84 static int setup_cpu_watcher(struct notifier_block *notifier,
85 unsigned long event, void *data)
86 {
87 int i;
89 static struct xenbus_watch cpu_watch = {
90 .node = "cpu",
91 .callback = handle_vcpu_hotplug_event,
92 .flags = XBWF_new_thread };
93 (void)register_xenbus_watch(&cpu_watch);
95 if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
96 for_each_cpu(i)
97 vcpu_hotplug(i);
98 printk(KERN_INFO "Brought up %ld CPUs\n",
99 (long)num_online_cpus());
100 }
102 return NOTIFY_DONE;
103 }
105 static int __init setup_vcpu_hotplug_event(void)
106 {
107 static struct notifier_block hotplug_cpu = {
108 .notifier_call = smpboot_cpu_notify };
109 static struct notifier_block xsn_cpu = {
110 .notifier_call = setup_cpu_watcher };
112 if (!is_running_on_xen())
113 return -ENODEV;
115 register_cpu_notifier(&hotplug_cpu);
116 register_xenstore_notifier(&xsn_cpu);
118 return 0;
119 }
121 arch_initcall(setup_vcpu_hotplug_event);
123 int smp_suspend(void)
124 {
125 int i, err;
127 lock_cpu_hotplug();
129 /*
130 * Take all other CPUs offline. We hold the hotplug mutex to
131 * avoid other processes bringing up CPUs under our feet.
132 */
133 while (num_online_cpus() > 1) {
134 unlock_cpu_hotplug();
135 for_each_online_cpu(i) {
136 if (i == 0)
137 continue;
138 err = cpu_down(i);
139 if (err) {
140 printk(KERN_CRIT "Failed to take all CPUs "
141 "down: %d.\n", err);
142 for_each_cpu(i)
143 vcpu_hotplug(i);
144 return err;
145 }
146 }
147 lock_cpu_hotplug();
148 }
150 return 0;
151 }
153 void smp_resume(void)
154 {
155 int cpu;
157 for_each_cpu(cpu)
158 cpu_initialize_context(cpu);
160 unlock_cpu_hotplug();
162 for_each_cpu(cpu)
163 vcpu_hotplug(cpu);
164 }
166 int cpu_up_check(unsigned int cpu)
167 {
168 int rc = 0;
170 if (local_cpu_hotplug_request()) {
171 cpu_set(cpu, local_allowed_cpumask);
172 if (!cpu_isset(cpu, xenbus_allowed_cpumask)) {
173 printk("%s: attempt to bring up CPU %u disallowed by "
174 "remote admin.\n", __FUNCTION__, cpu);
175 rc = -EBUSY;
176 }
177 } else if (!cpu_isset(cpu, local_allowed_cpumask) ||
178 !cpu_isset(cpu, xenbus_allowed_cpumask)) {
179 rc = -EBUSY;
180 }
182 return rc;
183 }
185 void init_xenbus_allowed_cpumask(void)
186 {
187 xenbus_allowed_cpumask = cpu_present_map;
188 }