manage.c 7.2 KB
Newer Older
1 2 3
/*
 * Handle extern requests for shutdown, reboot and sysrq
 */
J
Joe Perches 已提交
4 5 6

#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt

7 8
#include <linux/kernel.h>
#include <linux/err.h>
9
#include <linux/slab.h>
10 11
#include <linux/reboot.h>
#include <linux/sysrq.h>
12 13
#include <linux/stop_machine.h>
#include <linux/freezer.h>
14
#include <linux/syscore_ops.h>
15
#include <linux/export.h>
16

17
#include <xen/xen.h>
18
#include <xen/xenbus.h>
19 20 21 22
#include <xen/grant_table.h>
#include <xen/events.h>
#include <xen/hvc-console.h>
#include <xen/xen-ops.h>
23

24 25
#include <asm/xen/hypercall.h>
#include <asm/xen/page.h>
26
#include <asm/xen/hypervisor.h>
27 28 29 30 31 32 33 34 35 36 37

enum shutdown_state {
	SHUTDOWN_INVALID = -1,
	SHUTDOWN_POWEROFF = 0,
	SHUTDOWN_SUSPEND = 2,
	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
	   report a crash, not be instructed to crash!
	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
	   the distinction when we return the reason code to them.  */
	 SHUTDOWN_HALT = 4,
};
38 39

/* Ignore multiple shutdown requests. */
40 41
static enum shutdown_state shutting_down = SHUTDOWN_INVALID;

42 43 44 45
struct suspend_info {
	int cancelled;
};

46 47 48 49 50 51 52 53 54 55 56 57 58 59
static RAW_NOTIFIER_HEAD(xen_resume_notifier);

void xen_resume_notifier_register(struct notifier_block *nb)
{
	raw_notifier_chain_register(&xen_resume_notifier, nb);
}
EXPORT_SYMBOL_GPL(xen_resume_notifier_register);

void xen_resume_notifier_unregister(struct notifier_block *nb)
{
	raw_notifier_chain_unregister(&xen_resume_notifier, nb);
}
EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister);

60
#ifdef CONFIG_HIBERNATE_CALLBACKS
61 62
static int xen_suspend(void *data)
{
63
	struct suspend_info *si = data;
64
	int err;
65 66 67

	BUG_ON(!irqs_disabled());

68
	err = syscore_suspend();
69
	if (err) {
J
Joe Perches 已提交
70
		pr_err("%s: system core suspend failed: %d\n", __func__, err);
71 72
		return err;
	}
73

74 75
	gnttab_suspend();
	xen_arch_pre_suspend();
76 77 78 79 80 81

	/*
	 * This hypercall returns 1 if suspend was cancelled
	 * or the domain was merely checkpointed, and 0 if it
	 * is resuming in a new domain.
	 */
82 83 84
	si->cancelled = HYPERVISOR_suspend(xen_pv_domain()
                                           ? virt_to_mfn(xen_start_info)
                                           : 0);
85

86 87
	xen_arch_post_suspend(si->cancelled);
	gnttab_resume();
88

89
	if (!si->cancelled) {
90 91
		xen_irq_resume();
		xen_console_resume();
92
		xen_timer_resume();
93 94
	}

95
	syscore_resume();
96

97 98 99 100 101 102
	return 0;
}

static void do_suspend(void)
{
	int err;
103
	struct suspend_info si;
104 105 106 107 108 109 110 111 112

	shutting_down = SHUTDOWN_SUSPEND;

#ifdef CONFIG_PREEMPT
	/* If the kernel is preemptible, we need to freeze all the processes
	   to prevent them from being in the middle of a pagetable update
	   during suspend. */
	err = freeze_processes();
	if (err) {
J
Joe Perches 已提交
113
		pr_err("%s: freeze failed %d\n", __func__, err);
114
		goto out;
115 116 117
	}
#endif

118
	err = dpm_suspend_start(PMSG_FREEZE);
119
	if (err) {
J
Joe Perches 已提交
120
		pr_err("%s: dpm_suspend_start %d\n", __func__, err);
121
		goto out_thaw;
122 123
	}

I
Ian Campbell 已提交
124 125 126
	printk(KERN_DEBUG "suspending xenstore...\n");
	xs_suspend();

127
	err = dpm_suspend_end(PMSG_FREEZE);
128
	if (err) {
J
Joe Perches 已提交
129
		pr_err("dpm_suspend_end failed: %d\n", err);
130
		si.cancelled = 0;
131
		goto out_resume;
132 133
	}

134 135
	si.cancelled = 1;

136
	err = stop_machine(xen_suspend, &si, cpumask_of(0));
137

138 139
	raw_notifier_call_chain(&xen_resume_notifier, 0, NULL);

140
	dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
141

142
	if (err) {
J
Joe Perches 已提交
143
		pr_err("failed to start xen_suspend: %d\n", err);
144
		si.cancelled = 1;
145 146
	}

I
Ian Campbell 已提交
147
out_resume:
148
	if (!si.cancelled) {
149
		xen_arch_resume();
150
		xs_resume();
151
	} else
152
		xs_suspend_cancel();
153

154
	dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
155

156
out_thaw:
157 158
#ifdef CONFIG_PREEMPT
	thaw_processes();
159
out:
160
#endif
161 162
	shutting_down = SHUTDOWN_INVALID;
}
163
#endif	/* CONFIG_HIBERNATE_CALLBACKS */
164

165 166 167 168 169
struct shutdown_handler {
	const char *command;
	void (*cb)(void);
};

170 171 172 173 174 175 176 177 178 179 180 181
static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused)
{
	switch (code) {
	case SYS_DOWN:
	case SYS_HALT:
	case SYS_POWER_OFF:
		shutting_down = SHUTDOWN_POWEROFF;
	default:
		break;
	}
	return NOTIFY_DONE;
}
182 183
static void do_poweroff(void)
{
184 185 186 187 188 189 190 191 192 193 194 195
	switch (system_state) {
	case SYSTEM_BOOTING:
		orderly_poweroff(true);
		break;
	case SYSTEM_RUNNING:
		orderly_poweroff(false);
		break;
	default:
		/* Don't do it when we are halting/rebooting. */
		pr_info("Ignoring Xen toolstack shutdown.\n");
		break;
	}
196 197 198 199 200 201 202 203
}

static void do_reboot(void)
{
	shutting_down = SHUTDOWN_POWEROFF; /* ? */
	ctrl_alt_del();
}

204 205 206 207 208 209
static void shutdown_handler(struct xenbus_watch *watch,
			     const char **vec, unsigned int len)
{
	char *str;
	struct xenbus_transaction xbt;
	int err;
210 211 212 213
	static struct shutdown_handler handlers[] = {
		{ "poweroff",	do_poweroff },
		{ "halt",	do_poweroff },
		{ "reboot",	do_reboot   },
214
#ifdef CONFIG_HIBERNATE_CALLBACKS
215 216 217 218 219
		{ "suspend",	do_suspend  },
#endif
		{NULL, NULL},
	};
	static struct shutdown_handler *handler;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

	if (shutting_down != SHUTDOWN_INVALID)
		return;

 again:
	err = xenbus_transaction_start(&xbt);
	if (err)
		return;

	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
	/* Ignore read errors and empty reads. */
	if (XENBUS_IS_ERR_READ(str)) {
		xenbus_transaction_end(xbt, 1);
		return;
	}

236 237 238 239 240 241 242 243
	for (handler = &handlers[0]; handler->command; handler++) {
		if (strcmp(str, handler->command) == 0)
			break;
	}

	/* Only acknowledge commands which we are prepared to handle. */
	if (handler->cb)
		xenbus_write(xbt, "control", "shutdown", "");
244 245 246 247 248 249 250

	err = xenbus_transaction_end(xbt, 0);
	if (err == -EAGAIN) {
		kfree(str);
		goto again;
	}

251 252
	if (handler->cb) {
		handler->cb();
253
	} else {
J
Joe Perches 已提交
254
		pr_info("Ignoring shutdown request: %s\n", str);
255 256 257 258 259 260
		shutting_down = SHUTDOWN_INVALID;
	}

	kfree(str);
}

261
#ifdef CONFIG_MAGIC_SYSRQ
262 263 264 265 266 267 268 269 270 271 272 273
static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
			  unsigned int len)
{
	char sysrq_key = '\0';
	struct xenbus_transaction xbt;
	int err;

 again:
	err = xenbus_transaction_start(&xbt);
	if (err)
		return;
	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
J
Joe Perches 已提交
274
		pr_err("Unable to read sysrq code in control/sysrq\n");
275 276 277 278 279 280 281 282 283 284 285 286
		xenbus_transaction_end(xbt, 1);
		return;
	}

	if (sysrq_key != '\0')
		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');

	err = xenbus_transaction_end(xbt, 0);
	if (err == -EAGAIN)
		goto again;

	if (sysrq_key != '\0')
287
		handle_sysrq(sysrq_key);
288 289 290 291 292 293
}

static struct xenbus_watch sysrq_watch = {
	.node = "control/sysrq",
	.callback = sysrq_handler
};
294 295 296 297 298 299
#endif

static struct xenbus_watch shutdown_watch = {
	.node = "control/shutdown",
	.callback = shutdown_handler
};
300

301 302 303 304
static struct notifier_block xen_reboot_nb = {
	.notifier_call = poweroff_nb,
};

305 306 307 308 309 310
static int setup_shutdown_watcher(void)
{
	int err;

	err = register_xenbus_watch(&shutdown_watch);
	if (err) {
J
Joe Perches 已提交
311
		pr_err("Failed to set shutdown watcher\n");
312 313 314
		return err;
	}

315

316
#ifdef CONFIG_MAGIC_SYSRQ
317 318
	err = register_xenbus_watch(&sysrq_watch);
	if (err) {
J
Joe Perches 已提交
319
		pr_err("Failed to set sysrq watcher\n");
320 321
		return err;
	}
322
#endif
323 324 325 326 327 328 329 330 331 332 333 334

	return 0;
}

static int shutdown_event(struct notifier_block *notifier,
			  unsigned long event,
			  void *data)
{
	setup_shutdown_watcher();
	return NOTIFY_DONE;
}

335
int xen_setup_shutdown_event(void)
336 337 338 339
{
	static struct notifier_block xenstore_notifier = {
		.notifier_call = shutdown_event
	};
340 341 342

	if (!xen_domain())
		return -ENODEV;
343
	register_xenstore_notifier(&xenstore_notifier);
344
	register_reboot_notifier(&xen_reboot_nb);
345 346 347

	return 0;
}
348
EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
349

350
subsys_initcall(xen_setup_shutdown_event);