brintos

brintos / linux-shallow public Read only

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