[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] xen suspend: Fix suspend-via-evtchn reentrancy.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1217514834 -3600 # Node ID 2866e6af503ea0b33e1c1fb2340ab8ed81925e97 # Parent 44e3ace9a1f154941f7ccfb97cb75a8ab01ac3d1 xen suspend: Fix suspend-via-evtchn reentrancy. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- drivers/xen/core/machine_reboot.c | 9 +---- drivers/xen/core/reboot.c | 63 ++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 25 deletions(-) diff -r 44e3ace9a1f1 -r 2866e6af503e drivers/xen/core/machine_reboot.c --- a/drivers/xen/core/machine_reboot.c Thu Jul 31 09:46:58 2008 +0100 +++ b/drivers/xen/core/machine_reboot.c Thu Jul 31 15:33:54 2008 +0100 @@ -26,8 +26,6 @@ void (*pm_power_off)(void); void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); -int setup_suspend_evtchn(void); - void machine_emergency_restart(void) { /* We really want to get pending console data out before we die. */ @@ -133,7 +131,7 @@ static void post_suspend(int suspend_can struct suspend { int fast_suspend; - void (*resume_notifier)(void); + void (*resume_notifier)(int); }; static int take_machine_down(void *_suspend) @@ -175,7 +173,7 @@ static int take_machine_down(void *_susp */ suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); - suspend->resume_notifier(); + suspend->resume_notifier(suspend_cancelled); post_suspend(suspend_cancelled); gnttab_resume(); if (!suspend_cancelled) { @@ -204,7 +202,7 @@ static int take_machine_down(void *_susp return suspend_cancelled; } -int __xen_suspend(int fast_suspend, void (*resume_notifier)(void)) +int __xen_suspend(int fast_suspend, void (*resume_notifier)(int)) { int err, suspend_cancelled; struct suspend suspend; @@ -243,7 +241,6 @@ int __xen_suspend(int fast_suspend, void if (!suspend_cancelled) { xencons_resume(); xenbus_resume(); - setup_suspend_evtchn(); } else { xenbus_suspend_cancel(); } diff -r 44e3ace9a1f1 -r 2866e6af503e drivers/xen/core/reboot.c --- a/drivers/xen/core/reboot.c Thu Jul 31 09:46:58 2008 +0100 +++ b/drivers/xen/core/reboot.c Thu Jul 31 15:33:54 2008 +0100 @@ -27,13 +27,18 @@ MODULE_LICENSE("Dual BSD/GPL"); /* Ignore multiple shutdown requests. */ static int shutting_down = SHUTDOWN_INVALID; +/* Was last suspend request cancelled? */ +static int suspend_cancelled; + /* Can we leave APs online when we suspend? */ static int fast_suspend; static void __shutdown_handler(void *unused); static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL); -int __xen_suspend(int fast_suspend, void (*resume_notifier)(void)); +static int setup_suspend_evtchn(void); + +int __xen_suspend(int fast_suspend, void (*resume_notifier)(int)); static int shutdown_process(void *__unused) { @@ -62,10 +67,11 @@ static int shutdown_process(void *__unus return 0; } -static void xen_resume_notifier(void) +static void xen_resume_notifier(int _suspend_cancelled) { int old_state = xchg(&shutting_down, SHUTDOWN_RESUMING); BUG_ON(old_state != SHUTDOWN_SUSPEND); + suspend_cancelled = _suspend_cancelled; } static int xen_suspend(void *__unused) @@ -85,6 +91,8 @@ static int xen_suspend(void *__unused) printk(KERN_ERR "Xen suspend failed (%d)\n", err); goto fail; } + if (!suspend_cancelled) + setup_suspend_evtchn(); old_state = cmpxchg( &shutting_down, SHUTDOWN_RESUMING, SHUTDOWN_INVALID); } while (old_state == SHUTDOWN_SUSPEND); @@ -108,6 +116,31 @@ static int xen_suspend(void *__unused) return 0; } +static void switch_shutdown_state(int new_state) +{ + int prev_state, old_state = SHUTDOWN_INVALID; + + /* We only drive shutdown_state into an active state. */ + if (new_state == SHUTDOWN_INVALID) + return; + + do { + /* We drop this transition if already in an active state. */ + if ((old_state != SHUTDOWN_INVALID) && + (old_state != SHUTDOWN_RESUMING)) + return; + /* Attempt to transition. */ + prev_state = old_state; + old_state = cmpxchg(&shutting_down, old_state, new_state); + } while (old_state != prev_state); + + /* Either we kick off the work, or we leave it to xen_suspend(). */ + if (old_state == SHUTDOWN_INVALID) + schedule_work(&shutdown_work); + else + BUG_ON(old_state != SHUTDOWN_RESUMING); +} + static void __shutdown_handler(void *unused) { int err; @@ -129,7 +162,7 @@ static void shutdown_handler(struct xenb extern void ctrl_alt_del(void); char *str; struct xenbus_transaction xbt; - int err, old_state, new_state = SHUTDOWN_INVALID; + int err, new_state = SHUTDOWN_INVALID; if ((shutting_down != SHUTDOWN_INVALID) && (shutting_down != SHUTDOWN_RESUMING)) @@ -166,13 +199,7 @@ static void shutdown_handler(struct xenb else printk("Ignoring shutdown request: %s\n", str); - if (new_state != SHUTDOWN_INVALID) { - old_state = xchg(&shutting_down, new_state); - if (old_state == SHUTDOWN_INVALID) - schedule_work(&shutdown_work); - else - BUG_ON(old_state != SHUTDOWN_RESUMING); - } + switch_shutdown_state(new_state); kfree(str); } @@ -220,26 +247,24 @@ static struct xenbus_watch sysrq_watch = static irqreturn_t suspend_int(int irq, void* dev_id, struct pt_regs *ptregs) { - shutting_down = SHUTDOWN_SUSPEND; - schedule_work(&shutdown_work); - + switch_shutdown_state(SHUTDOWN_SUSPEND); return IRQ_HANDLED; } -int setup_suspend_evtchn(void) -{ - static int irq = -1; +static int setup_suspend_evtchn(void) +{ + static int irq; int port; - char portstr[5]; /* 1024 max */ + char portstr[16]; if (irq > 0) unbind_from_irqhandler(irq, NULL); irq = bind_listening_port_to_irqhandler(0, suspend_int, 0, "suspend", NULL); - if (irq <= 0) { + if (irq <= 0) return -1; - } + port = irq_to_evtchn_port(irq); printk(KERN_INFO "suspend: event channel %d\n", port); sprintf(portstr, "%d", port); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |