File Index
Files and directories
Sign in
FILE

manage.c

File preview with syntax highlighting.

linux-6.19.14/drivers/xen/manage.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Handle extern requests for shutdown, reboot and sysrq
  4 */
  5
  6#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
  7
  8#include <linux/kernel.h>
  9#include <linux/err.h>
 10#include <linux/slab.h>
 11#include <linux/reboot.h>
 12#include <linux/sysrq.h>
 13#include <linux/stop_machine.h>
 14#include <linux/suspend.h>
 15#include <linux/freezer.h>
 16#include <linux/syscore_ops.h>
 17#include <linux/export.h>
 18
 19#include <xen/xen.h>
 20#include <xen/xenbus.h>
 21#include <xen/grant_table.h>
 22#include <xen/events.h>
 23#include <xen/hvc-console.h>
 24#include <xen/page.h>
 25#include <xen/xen-ops.h>
 26
 27#include <asm/xen/hypercall.h>
 28#include <asm/xen/hypervisor.h>
 29
 30enum shutdown_state {
 31	SHUTDOWN_INVALID = -1,
 32	SHUTDOWN_POWEROFF = 0,
 33	SHUTDOWN_SUSPEND = 2,
 34	/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
 35	   report a crash, not be instructed to crash!
 36	   HALT is the same as POWEROFF, as far as we're concerned.  The tools use
 37	   the distinction when we return the reason code to them.  */
 38	 SHUTDOWN_HALT = 4,
 39};
 40
 41/* Ignore multiple shutdown requests. */
 42static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
 43
 44struct suspend_info {
 45	int cancelled;
 46};
 47
 48static RAW_NOTIFIER_HEAD(xen_resume_notifier);
 49
 50void xen_resume_notifier_register(struct notifier_block *nb)
 51{
 52	raw_notifier_chain_register(&xen_resume_notifier, nb);
 53}
 54EXPORT_SYMBOL_GPL(xen_resume_notifier_register);
 55
 56#ifdef CONFIG_HIBERNATE_CALLBACKS
 57static int xen_suspend(void *data)
 58{
 59	struct suspend_info *si = data;
 60	int err;
 61
 62	BUG_ON(!irqs_disabled());
 63
 64	err = syscore_suspend();
 65	if (err) {
 66		pr_err("%s: system core suspend failed: %d\n", __func__, err);
 67		return err;
 68	}
 69
 70	gnttab_suspend();
 71	xen_manage_runstate_time(-1);
 72	xen_arch_pre_suspend();
 73
 74	si->cancelled = HYPERVISOR_suspend(xen_pv_domain()
 75                                           ? virt_to_gfn(xen_start_info)
 76                                           : 0);
 77
 78	xen_arch_post_suspend(si->cancelled);
 79	xen_manage_runstate_time(si->cancelled ? 1 : 0);
 80	gnttab_resume();
 81
 82	if (!si->cancelled) {
 83		xen_irq_resume();
 84		xen_timer_resume();
 85	}
 86
 87	syscore_resume();
 88
 89	return 0;
 90}
 91
 92static void do_suspend(void)
 93{
 94	int err;
 95	struct suspend_info si;
 96
 97	shutting_down = SHUTDOWN_SUSPEND;
 98
 99	if (!mutex_trylock(&system_transition_mutex))
100	{
101		pr_err("%s: failed to take system_transition_mutex\n", __func__);
102		goto out;
103	}
104
105	err = freeze_processes();
106	if (err) {
107		pr_err("%s: freeze processes failed %d\n", __func__, err);
108		goto out_unlock;
109	}
110
111	err = freeze_kernel_threads();
112	if (err) {
113		pr_err("%s: freeze kernel threads failed %d\n", __func__, err);
114		goto out_thaw;
115	}
116
117	err = dpm_suspend_start(PMSG_FREEZE);
118	if (err) {
119		pr_err("%s: dpm_suspend_start %d\n", __func__, err);
120		goto out_resume_end;
121	}
122
123	printk(KERN_DEBUG "suspending xenstore...\n");
124	xs_suspend();
125
126	err = dpm_suspend_end(PMSG_FREEZE);
127	if (err) {
128		pr_err("dpm_suspend_end failed: %d\n", err);
129		si.cancelled = 0;
130		goto out_resume;
131	}
132
133	xen_arch_suspend();
134
135	si.cancelled = 1;
136
137	err = stop_machine(xen_suspend, &si, cpumask_of(0));
138
139	/* Resume console as early as possible. */
140	if (!si.cancelled)
141		xen_console_resume();
142
143	raw_notifier_call_chain(&xen_resume_notifier, 0, NULL);
144
145	xen_arch_resume();
146
147	dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
148
149	if (err) {
150		pr_err("failed to start xen_suspend: %d\n", err);
151		si.cancelled = 1;
152	}
153
154out_resume:
155	if (!si.cancelled)
156		xs_resume();
157	else
158		xs_suspend_cancel();
159
160out_resume_end:
161	dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
162
163out_thaw:
164	thaw_processes();
165out_unlock:
166	mutex_unlock(&system_transition_mutex);
167out:
168	shutting_down = SHUTDOWN_INVALID;
169}
170#endif	/* CONFIG_HIBERNATE_CALLBACKS */
171
172struct shutdown_handler {
173#define SHUTDOWN_CMD_SIZE 11
174	const char command[SHUTDOWN_CMD_SIZE];
175	bool flag;
176	void (*cb)(void);
177};
178
179static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused)
180{
181	switch (code) {
182	case SYS_DOWN:
183	case SYS_HALT:
184	case SYS_POWER_OFF:
185		shutting_down = SHUTDOWN_POWEROFF;
186		break;
187	default:
188		break;
189	}
190	return NOTIFY_DONE;
191}
192static void do_poweroff(void)
193{
194	switch (system_state) {
195	case SYSTEM_BOOTING:
196	case SYSTEM_SCHEDULING:
197		orderly_poweroff(true);
198		break;
199	case SYSTEM_RUNNING:
200		orderly_poweroff(false);
201		break;
202	default:
203		/* Don't do it when we are halting/rebooting. */
204		pr_info("Ignoring Xen toolstack shutdown.\n");
205		break;
206	}
207}
208
209static void do_reboot(void)
210{
211	shutting_down = SHUTDOWN_POWEROFF; /* ? */
212	orderly_reboot();
213}
214
215static const struct shutdown_handler shutdown_handlers[] = {
216	{ "poweroff",	true,	do_poweroff },
217	{ "halt",	false,	do_poweroff },
218	{ "reboot",	true,	do_reboot   },
219#ifdef CONFIG_HIBERNATE_CALLBACKS
220	{ "suspend",	true,	do_suspend  },
221#endif
222};
223
224static void shutdown_handler(struct xenbus_watch *watch,
225			     const char *path, const char *token)
226{
227	char *str;
228	struct xenbus_transaction xbt;
229	int err;
230	int idx;
231
232	if (shutting_down != SHUTDOWN_INVALID)
233		return;
234
235 again:
236	err = xenbus_transaction_start(&xbt);
237	if (err)
238		return;
239
240	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
241	/* Ignore read errors and empty reads. */
242	if (XENBUS_IS_ERR_READ(str)) {
243		xenbus_transaction_end(xbt, 1);
244		return;
245	}
246
247	for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) {
248		if (strcmp(str, shutdown_handlers[idx].command) == 0)
249			break;
250	}
251
252	/* Only acknowledge commands which we are prepared to handle. */
253	if (idx < ARRAY_SIZE(shutdown_handlers))
254		xenbus_write(xbt, "control", "shutdown", "");
255
256	err = xenbus_transaction_end(xbt, 0);
257	if (err == -EAGAIN) {
258		kfree(str);
259		goto again;
260	}
261
262	if (idx < ARRAY_SIZE(shutdown_handlers)) {
263		shutdown_handlers[idx].cb();
264	} else {
265		pr_info("Ignoring shutdown request: %s\n", str);
266		shutting_down = SHUTDOWN_INVALID;
267	}
268
269	kfree(str);
270}
271
272#ifdef CONFIG_MAGIC_SYSRQ
273static void sysrq_handler(struct xenbus_watch *watch, const char *path,
274			  const char *token)
275{
276	char sysrq_key = '\0';
277	struct xenbus_transaction xbt;
278	int err;
279
280 again:
281	err = xenbus_transaction_start(&xbt);
282	if (err)
283		return;
284	err = xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key);
285	if (err < 0) {
286		/*
287		 * The Xenstore watch fires directly after registering it and
288		 * after a suspend/resume cycle. So ENOENT is no error but
289		 * might happen in those cases. ERANGE is observed when we get
290		 * an empty value (''), this happens when we acknowledge the
291		 * request by writing '\0' below.
292		 */
293		if (err != -ENOENT && err != -ERANGE)
294			pr_err("Error %d reading sysrq code in control/sysrq\n",
295			       err);
296		xenbus_transaction_end(xbt, 1);
297		return;
298	}
299
300	if (sysrq_key != '\0') {
301		err = xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
302		if (err) {
303			pr_err("%s: Error %d writing sysrq in control/sysrq\n",
304			       __func__, err);
305			xenbus_transaction_end(xbt, 1);
306			return;
307		}
308	}
309
310	err = xenbus_transaction_end(xbt, 0);
311	if (err == -EAGAIN)
312		goto again;
313
314	if (sysrq_key != '\0')
315		handle_sysrq(sysrq_key);
316}
317
318static struct xenbus_watch sysrq_watch = {
319	.node = "control/sysrq",
320	.callback = sysrq_handler
321};
322#endif
323
324static struct xenbus_watch shutdown_watch = {
325	.node = "control/shutdown",
326	.callback = shutdown_handler
327};
328
329static struct notifier_block xen_reboot_nb = {
330	.notifier_call = poweroff_nb,
331};
332
333static int setup_shutdown_watcher(void)
334{
335	int err;
336	int idx;
337#define FEATURE_PATH_SIZE (SHUTDOWN_CMD_SIZE + sizeof("feature-"))
338	char node[FEATURE_PATH_SIZE];
339
340	err = register_xenbus_watch(&shutdown_watch);
341	if (err) {
342		pr_err("Failed to set shutdown watcher\n");
343		return err;
344	}
345
346
347#ifdef CONFIG_MAGIC_SYSRQ
348	err = register_xenbus_watch(&sysrq_watch);
349	if (err) {
350		pr_err("Failed to set sysrq watcher\n");
351		return err;
352	}
353#endif
354
355	for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) {
356		if (!shutdown_handlers[idx].flag)
357			continue;
358		snprintf(node, FEATURE_PATH_SIZE, "feature-%s",
359			 shutdown_handlers[idx].command);
360		err = xenbus_printf(XBT_NIL, "control", node, "%u", 1);
361		if (err) {
362			pr_err("%s: Error %d writing %s\n", __func__,
363				err, node);
364			return err;
365		}
366	}
367
368	return 0;
369}
370
371static int shutdown_event(struct notifier_block *notifier,
372			  unsigned long event,
373			  void *data)
374{
375	setup_shutdown_watcher();
376	return NOTIFY_DONE;
377}
378
379int xen_setup_shutdown_event(void)
380{
381	static struct notifier_block xenstore_notifier = {
382		.notifier_call = shutdown_event
383	};
384
385	if (!xen_domain())
386		return -ENODEV;
387	register_xenstore_notifier(&xenstore_notifier);
388	register_reboot_notifier(&xen_reboot_nb);
389
390	return 0;
391}
392EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
393
394subsys_initcall(xen_setup_shutdown_event);
~/ Read-only file preview.