manage.c revision 1f112cee07b314e244ee9e71d9c1e6950dc13327
13e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* 23e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge * Handle extern requests for shutdown, reboot and sysrq 33e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge */ 43e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/kernel.h> 53e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/err.h> 65a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 73e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/reboot.h> 83e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <linux/sysrq.h> 90e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/stop_machine.h> 100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <linux/freezer.h> 113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 12016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini#include <xen/xen.h> 133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge#include <xen/xenbus.h> 140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/grant_table.h> 150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/events.h> 160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/hvc-console.h> 170e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <xen/xen-ops.h> 183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/hypercall.h> 200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#include <asm/xen/page.h> 21016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini#include <asm/xen/hypervisor.h> 220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 230e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingeenum shutdown_state { 240e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_INVALID = -1, 250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_POWEROFF = 0, 260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_SUSPEND = 2, 270e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 280e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge report a crash, not be instructed to crash! 290e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge HALT is the same as POWEROFF, as far as we're concerned. The tools use 300e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge the distinction when we return the reason code to them. */ 310e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge SHUTDOWN_HALT = 4, 320e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge}; 333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 343e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge/* Ignore multiple shutdown requests. */ 350e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic enum shutdown_state shutting_down = SHUTDOWN_INVALID; 360e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 37ceb180294790c8a6a437533488616f6b591b49d0Ian Campbellstruct suspend_info { 38ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell int cancelled; 3936b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell unsigned long arg; /* extra hypercall argument */ 4055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell void (*pre)(void); 4155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell void (*post)(int cancelled); 42ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell}; 43ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell 4407af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbellstatic void xen_hvm_post_suspend(int cancelled) 4582043bb60d24d2897074905c94be5a53071e8913Ian Campbell{ 4607af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell xen_arch_hvm_post_suspend(cancelled); 4782043bb60d24d2897074905c94be5a53071e8913Ian Campbell gnttab_resume(); 4882043bb60d24d2897074905c94be5a53071e8913Ian Campbell} 4982043bb60d24d2897074905c94be5a53071e8913Ian Campbell 5082043bb60d24d2897074905c94be5a53071e8913Ian Campbellstatic void xen_pre_suspend(void) 5182043bb60d24d2897074905c94be5a53071e8913Ian Campbell{ 5282043bb60d24d2897074905c94be5a53071e8913Ian Campbell xen_mm_pin_all(); 5382043bb60d24d2897074905c94be5a53071e8913Ian Campbell gnttab_suspend(); 5407af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell xen_arch_pre_suspend(); 5582043bb60d24d2897074905c94be5a53071e8913Ian Campbell} 5682043bb60d24d2897074905c94be5a53071e8913Ian Campbell 5707af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbellstatic void xen_post_suspend(int cancelled) 5882043bb60d24d2897074905c94be5a53071e8913Ian Campbell{ 5907af38102fc4f260cc5a2418ec833707f53cdf70Ian Campbell xen_arch_post_suspend(cancelled); 6082043bb60d24d2897074905c94be5a53071e8913Ian Campbell gnttab_resume(); 6182043bb60d24d2897074905c94be5a53071e8913Ian Campbell xen_mm_unpin_all(); 6282043bb60d24d2897074905c94be5a53071e8913Ian Campbell} 6382043bb60d24d2897074905c94be5a53071e8913Ian Campbell 641f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#ifdef CONFIG_HIBERNATE_CALLBACKS 65016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellinistatic int xen_suspend(void *data) 66016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabellini{ 67ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell struct suspend_info *si = data; 68359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge int err; 690e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge BUG_ON(!irqs_disabled()); 710e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 72b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan err = sysdev_suspend(PMSG_FREEZE); 73770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki if (err) { 74770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", 75770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki err); 76770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki return err; 77770824bdc421ff58a64db608294323571c949f4cRafael J. Wysocki } 78359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge 7955fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell if (si->pre) 8055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si->pre(); 810e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 820e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge /* 830e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge * This hypercall returns 1 if suspend was cancelled 840e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge * or the domain was merely checkpointed, and 0 if it 850e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge * is resuming in a new domain. 860e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge */ 8736b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell si->cancelled = HYPERVISOR_suspend(si->arg); 880e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 8955fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell if (si->post) 9055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si->post(si->cancelled); 910e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 92ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell if (!si->cancelled) { 930e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge xen_irq_resume(); 940e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge xen_console_resume(); 95ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata xen_timer_resume(); 960e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 970e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 981e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell sysdev_resume(); 991e6fcf840e11ceff8a656a678c6e4b0560a98e08Ian Campbell 1000e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge return 0; 1010e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge} 1020e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 1030e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardingestatic void do_suspend(void) 1040e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge{ 1050e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge int err; 106ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell struct suspend_info si; 1070e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 1080e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge shutting_down = SHUTDOWN_SUSPEND; 1090e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 1100e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT 1110e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge /* If the kernel is preemptible, we need to freeze all the processes 1120e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge to prevent them from being in the middle of a pagetable update 1130e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge during suspend. */ 1140e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge err = freeze_processes(); 1150e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge if (err) { 1160e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge printk(KERN_ERR "xen suspend: freeze failed %d\n", err); 1173fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo goto out; 1180e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 1190e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#endif 1200e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 121b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan err = dpm_suspend_start(PMSG_FREEZE); 1220e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge if (err) { 123d161630297a20802d01c55847bfcba85d2118a9fAlan Stern printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err); 12465f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell goto out_thaw; 1250e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 1260e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 127c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell printk(KERN_DEBUG "suspending xenstore...\n"); 128c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell xs_suspend(); 129c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbell 130b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan err = dpm_suspend_noirq(PMSG_FREEZE); 1312ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki if (err) { 132d161630297a20802d01c55847bfcba85d2118a9fAlan Stern printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err); 13365f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell goto out_resume; 1342ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki } 1352ed8d2b3a81bdbb0418301628ccdb008ac9f40b7Rafael J. Wysocki 136ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell si.cancelled = 1; 137ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell 13855fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell if (xen_hvm_domain()) { 13936b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell si.arg = 0UL; 14055fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.pre = NULL; 14155fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.post = &xen_hvm_post_suspend; 14255fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell } else { 14336b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell si.arg = virt_to_mfn(xen_start_info); 14455fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.pre = &xen_pre_suspend; 14555fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell si.post = &xen_post_suspend; 14655fb4acef7089a6d4d93ed8caae6c258d06cfaf7Ian Campbell } 14736b401e2c2788c7b4881115ddbbff603fe4cf78dIan Campbell 148b056b6a0144de90707cd22cf7b4f60bf69c86d59Ian Campbell err = stop_machine(xen_suspend, &si, cpumask_of(0)); 149922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge 150b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 151922cc38ab71d1360978e65207e4a4f4988987127Jeremy Fitzhardinge 1520e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge if (err) { 1530e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge printk(KERN_ERR "failed to start xen_suspend: %d\n", err); 154ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell si.cancelled = 1; 1550e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } 1560e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 157c5cae661d6cf808b6984762f763261adf35f3eb7Ian Campbellout_resume: 158ceb180294790c8a6a437533488616f6b591b49d0Ian Campbell if (!si.cancelled) { 159ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata xen_arch_resume(); 160de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell xs_resume(); 161ad55db9fed6d6cd09333045945cb03ba2c070085Isaku Yamahata } else 162de5b31bd47de7e6f41be2e271318dbc8f1af354dIan Campbell xs_suspend_cancel(); 1630e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 164b3e96c0c756211e805c6941d4a6e5f6e1995cb6bShriram Rajagopalan dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 1650e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge 166359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge /* Make sure timer events get retriggered on all CPUs */ 167359cdd3f866b6219a6729e313faf2221397f3278Jeremy Fitzhardinge clock_was_set(); 16865f63384b391bf4d384327d8a7c6de9860290b5cIan Campbell 16965f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout_thaw: 1700e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge#ifdef CONFIG_PREEMPT 1710e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge thaw_processes(); 17265f63384b391bf4d384327d8a7c6de9860290b5cIan Campbellout: 1733fc1f1e27a5b807791d72e5d992aa33b668a6626Tejun Heo#endif 1740e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 1750e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge} 1761f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#endif /* CONFIG_HIBERNATE_CALLBACKS */ 1773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 178552717231e50b478dfd19d63fd97879476ae051dIan Campbellstruct shutdown_handler { 179552717231e50b478dfd19d63fd97879476ae051dIan Campbell const char *command; 180552717231e50b478dfd19d63fd97879476ae051dIan Campbell void (*cb)(void); 181552717231e50b478dfd19d63fd97879476ae051dIan Campbell}; 182552717231e50b478dfd19d63fd97879476ae051dIan Campbell 183552717231e50b478dfd19d63fd97879476ae051dIan Campbellstatic void do_poweroff(void) 184552717231e50b478dfd19d63fd97879476ae051dIan Campbell{ 185552717231e50b478dfd19d63fd97879476ae051dIan Campbell shutting_down = SHUTDOWN_POWEROFF; 186552717231e50b478dfd19d63fd97879476ae051dIan Campbell orderly_poweroff(false); 187552717231e50b478dfd19d63fd97879476ae051dIan Campbell} 188552717231e50b478dfd19d63fd97879476ae051dIan Campbell 189552717231e50b478dfd19d63fd97879476ae051dIan Campbellstatic void do_reboot(void) 190552717231e50b478dfd19d63fd97879476ae051dIan Campbell{ 191552717231e50b478dfd19d63fd97879476ae051dIan Campbell shutting_down = SHUTDOWN_POWEROFF; /* ? */ 192552717231e50b478dfd19d63fd97879476ae051dIan Campbell ctrl_alt_del(); 193552717231e50b478dfd19d63fd97879476ae051dIan Campbell} 194552717231e50b478dfd19d63fd97879476ae051dIan Campbell 1953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void shutdown_handler(struct xenbus_watch *watch, 1963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge const char **vec, unsigned int len) 1973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 1983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge char *str; 1993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge struct xenbus_transaction xbt; 2003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge int err; 201552717231e50b478dfd19d63fd97879476ae051dIan Campbell static struct shutdown_handler handlers[] = { 202552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "poweroff", do_poweroff }, 203552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "halt", do_poweroff }, 204552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "reboot", do_reboot }, 2051f112cee07b314e244ee9e71d9c1e6950dc13327Rafael J. Wysocki#ifdef CONFIG_HIBERNATE_CALLBACKS 206552717231e50b478dfd19d63fd97879476ae051dIan Campbell { "suspend", do_suspend }, 207552717231e50b478dfd19d63fd97879476ae051dIan Campbell#endif 208552717231e50b478dfd19d63fd97879476ae051dIan Campbell {NULL, NULL}, 209552717231e50b478dfd19d63fd97879476ae051dIan Campbell }; 210552717231e50b478dfd19d63fd97879476ae051dIan Campbell static struct shutdown_handler *handler; 2113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (shutting_down != SHUTDOWN_INVALID) 2133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again: 2163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_start(&xbt); 2173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) 2183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); 2213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge /* Ignore read errors and empty reads. */ 2223e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (XENBUS_IS_ERR_READ(str)) { 2233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge xenbus_transaction_end(xbt, 1); 2243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 227552717231e50b478dfd19d63fd97879476ae051dIan Campbell for (handler = &handlers[0]; handler->command; handler++) { 228552717231e50b478dfd19d63fd97879476ae051dIan Campbell if (strcmp(str, handler->command) == 0) 229552717231e50b478dfd19d63fd97879476ae051dIan Campbell break; 230552717231e50b478dfd19d63fd97879476ae051dIan Campbell } 231552717231e50b478dfd19d63fd97879476ae051dIan Campbell 232552717231e50b478dfd19d63fd97879476ae051dIan Campbell /* Only acknowledge commands which we are prepared to handle. */ 233552717231e50b478dfd19d63fd97879476ae051dIan Campbell if (handler->cb) 234552717231e50b478dfd19d63fd97879476ae051dIan Campbell xenbus_write(xbt, "control", "shutdown", ""); 2353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2363e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_end(xbt, 0); 2373e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err == -EAGAIN) { 2383e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge kfree(str); 2393e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge goto again; 2403e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2413e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 242552717231e50b478dfd19d63fd97879476ae051dIan Campbell if (handler->cb) { 243552717231e50b478dfd19d63fd97879476ae051dIan Campbell handler->cb(); 2440e91398f2a5d4eb6b07df8115917d0d1cf3e9b58Jeremy Fitzhardinge } else { 2453e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_INFO "Ignoring shutdown request: %s\n", str); 2463e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 2473e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2483e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2493e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge kfree(str); 2503e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 2513e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 252f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ 2533e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic void sysrq_handler(struct xenbus_watch *watch, const char **vec, 2543e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge unsigned int len) 2553e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 2563e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge char sysrq_key = '\0'; 2573e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge struct xenbus_transaction xbt; 2583e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge int err; 2593e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2603e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge again: 2613e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_start(&xbt); 2623e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) 2633e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2643e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { 2653e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_ERR "Unable to read sysrq code in " 2663e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge "control/sysrq\n"); 2673e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge xenbus_transaction_end(xbt, 1); 2683e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return; 2693e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 2703e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2713e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (sysrq_key != '\0') 2723e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); 2733e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2743e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = xenbus_transaction_end(xbt, 0); 2753e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err == -EAGAIN) 2763e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge goto again; 2773e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2783e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (sysrq_key != '\0') 279f335397d177c906256ee1bba28e8c49e8ec63817Dmitry Torokhov handle_sysrq(sysrq_key); 2803e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 2813e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2823e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic struct xenbus_watch sysrq_watch = { 2833e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge .node = "control/sysrq", 2843e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge .callback = sysrq_handler 2853e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge}; 286f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif 287f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap 288f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlapstatic struct xenbus_watch shutdown_watch = { 289f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap .node = "control/shutdown", 290f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap .callback = shutdown_handler 291f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap}; 2923e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2933e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int setup_shutdown_watcher(void) 2943e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 2953e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge int err; 2963e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 2973e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = register_xenbus_watch(&shutdown_watch); 2983e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) { 2993e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_ERR "Failed to set shutdown watcher\n"); 3003e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return err; 3013e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 3023e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 303f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#ifdef CONFIG_MAGIC_SYSRQ 3043e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge err = register_xenbus_watch(&sysrq_watch); 3053e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge if (err) { 3063e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge printk(KERN_ERR "Failed to set sysrq watcher\n"); 3073e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return err; 3083e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge } 309f3bc3189a001ec85c7b1119ad4aa5e39eea0f05eRandy Dunlap#endif 3103e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3113e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return 0; 3123e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 3133e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3143e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardingestatic int shutdown_event(struct notifier_block *notifier, 3153e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge unsigned long event, 3163e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge void *data) 3173e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 3183e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge setup_shutdown_watcher(); 3193e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return NOTIFY_DONE; 3203e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 3213e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 322016b6f5fe8398b0291cece60b749d7c930a2e09cStefano Stabelliniint xen_setup_shutdown_event(void) 3233e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge{ 3243e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge static struct notifier_block xenstore_notifier = { 3253e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge .notifier_call = shutdown_event 3263e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge }; 327702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini 328702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini if (!xen_domain()) 329702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellini return -ENODEV; 3303e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge register_xenstore_notifier(&xenstore_notifier); 3313e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 3323e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge return 0; 3333e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge} 334183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3cStefano StabelliniEXPORT_SYMBOL_GPL(xen_setup_shutdown_event); 3353e2b8fbeec8f005672f2a2e862fb9c26a0bafedcJeremy Fitzhardinge 336702d4eb9b3de4398ab99cf0a4e799e552c7ab756Stefano Stabellinisubsys_initcall(xen_setup_shutdown_event); 337