source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/drivers/xen/core/cpu_hotplug.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 3.7 KB
Line 
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>
8
9/*
10 * Set of CPUs that remote admin software will allow us to bring online.
11 * Notified to us via xenbus.
12 */
13static cpumask_t xenbus_allowed_cpumask;
14
15/* Set of CPUs that local admin will allow us to bring online. */
16static cpumask_t local_allowed_cpumask = CPU_MASK_ALL;
17
18static 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}
26
27static void vcpu_hotplug(unsigned int cpu)
28{
29        int err;
30        char dir[32], state[32];
31
32        if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
33                return;
34
35        sprintf(dir, "cpu/%d", 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        }
41
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}
53
54static void handle_vcpu_hotplug_event(
55        struct xenbus_watch *watch, const char **vec, unsigned int len)
56{
57        int cpu;
58        char *cpustr;
59        const char *node = vec[XS_WATCH_PATH];
60
61        if ((cpustr = strstr(node, "cpu/")) != NULL) {
62                sscanf(cpustr, "cpu/%d", &cpu);
63                vcpu_hotplug(cpu);
64        }
65}
66
67static int smpboot_cpu_notify(struct notifier_block *notifier,
68                              unsigned long action, void *hcpu)
69{
70        int cpu = (long)hcpu;
71
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);
79
80        return NOTIFY_OK;
81}
82
83static int setup_cpu_watcher(struct notifier_block *notifier,
84                              unsigned long event, void *data)
85{
86        int i;
87
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);
93
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        }
100
101        return NOTIFY_DONE;
102}
103
104static 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 };
110
111        if (!is_running_on_xen())
112                return -ENODEV;
113
114        register_cpu_notifier(&hotplug_cpu);
115        register_xenstore_notifier(&xsn_cpu);
116
117        return 0;
118}
119
120arch_initcall(setup_vcpu_hotplug_event);
121
122int smp_suspend(void)
123{
124        int cpu, err;
125
126        for_each_online_cpu(cpu) {
127                if (cpu == 0)
128                        continue;
129                err = cpu_down(cpu);
130                if (err) {
131                        printk(KERN_CRIT "Failed to take all CPUs "
132                               "down: %d.\n", err);
133                        for_each_possible_cpu(cpu)
134                                vcpu_hotplug(cpu);
135                        return err;
136                }
137        }
138
139        return 0;
140}
141
142void smp_resume(void)
143{
144        int cpu;
145
146        for_each_possible_cpu(cpu)
147                vcpu_hotplug(cpu);
148}
149
150int cpu_up_check(unsigned int cpu)
151{
152        int rc = 0;
153
154        if (local_cpu_hotplug_request()) {
155                cpu_set(cpu, local_allowed_cpumask);
156                if (!cpu_isset(cpu, xenbus_allowed_cpumask)) {
157                        printk("%s: attempt to bring up CPU %u disallowed by "
158                               "remote admin.\n", __FUNCTION__, cpu);
159                        rc = -EBUSY;
160                }
161        } else if (!cpu_isset(cpu, local_allowed_cpumask) ||
162                   !cpu_isset(cpu, xenbus_allowed_cpumask)) {
163                rc = -EBUSY;
164        }
165
166        return rc;
167}
168
169void init_xenbus_allowed_cpumask(void)
170{
171        xenbus_allowed_cpumask = cpu_present_map;
172}
Note: See TracBrowser for help on using the repository browser.