[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] xen: Fix PV resume race against another back-to-back suspend request.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1204280953 0 # Node ID 49ffe9ef67d420bde98e7ead29c9b9bfc5b026ba # Parent 87721beab1b907e45f101ed4075a75adab828b59 xen: Fix PV resume race against another back-to-back suspend request. Previously the next suspend request was being dropped on the floor. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- drivers/xen/core/machine_reboot.c | 25 +++++++---- drivers/xen/core/reboot.c | 82 +++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 37 deletions(-) diff -r 87721beab1b9 -r 49ffe9ef67d4 drivers/xen/core/machine_reboot.c --- a/drivers/xen/core/machine_reboot.c Thu Feb 28 16:41:41 2008 +0000 +++ b/drivers/xen/core/machine_reboot.c Fri Feb 29 10:29:13 2008 +0000 @@ -129,13 +129,18 @@ static void post_suspend(int suspend_can #endif -static int take_machine_down(void *p_fast_suspend) -{ - int fast_suspend = *(int *)p_fast_suspend; +struct suspend { + int fast_suspend; + void (*resume_notifier)(void); +}; + +static int take_machine_down(void *_suspend) +{ + struct suspend *suspend = _suspend; int suspend_cancelled, err; extern void time_resume(void); - if (fast_suspend) { + if (suspend->fast_suspend) { BUG_ON(!irqs_disabled()); } else { BUG_ON(irqs_disabled()); @@ -168,6 +173,7 @@ static int take_machine_down(void *p_fas */ suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); + suspend->resume_notifier(); post_suspend(suspend_cancelled); gnttab_resume(); if (!suspend_cancelled) { @@ -178,7 +184,7 @@ static int take_machine_down(void *p_fas * We do it here just in case, but there's no need if we are * in fast-suspend mode as that implies a new enough Xen. */ - if (!fast_suspend) { + if (!suspend->fast_suspend) { struct mmuext_op op; op.cmd = MMUEXT_NEW_USER_BASEPTR; op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd( @@ -190,15 +196,16 @@ static int take_machine_down(void *p_fas } time_resume(); - if (!fast_suspend) + if (!suspend->fast_suspend) local_irq_enable(); return suspend_cancelled; } -int __xen_suspend(int fast_suspend) +int __xen_suspend(int fast_suspend, void (*resume_notifier)(void)) { int err, suspend_cancelled; + struct suspend suspend = { fast_suspend, resume_notifier }; BUG_ON(smp_processor_id() != 0); BUG_ON(in_interrupt()); @@ -217,11 +224,11 @@ int __xen_suspend(int fast_suspend) if (fast_suspend) { xenbus_suspend(); - err = stop_machine_run(take_machine_down, &fast_suspend, 0); + err = stop_machine_run(take_machine_down, &suspend, 0); if (err < 0) xenbus_suspend_cancel(); } else { - err = take_machine_down(&fast_suspend); + err = take_machine_down(&suspend); } if (err < 0) diff -r 87721beab1b9 -r 49ffe9ef67d4 drivers/xen/core/reboot.c --- a/drivers/xen/core/reboot.c Thu Feb 28 16:41:41 2008 +0000 +++ b/drivers/xen/core/reboot.c Fri Feb 29 10:29:13 2008 +0000 @@ -20,11 +20,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define SHUTDOWN_INVALID -1 #define SHUTDOWN_POWEROFF 0 #define 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. - */ +#define SHUTDOWN_RESUMING 3 #define SHUTDOWN_HALT 4 /* Ignore multiple shutdown requests. */ @@ -36,7 +32,7 @@ static void __shutdown_handler(void *unu static void __shutdown_handler(void *unused); static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL); -int __xen_suspend(int fast_suspend); +int __xen_suspend(int fast_suspend, void (*resume_notifier)(void)); static int shutdown_process(void *__unused) { @@ -65,23 +61,49 @@ static int shutdown_process(void *__unus return 0; } +static void xen_resume_notifier(void) +{ + int old_state = xchg(&shutting_down, SHUTDOWN_RESUMING); + BUG_ON(old_state != SHUTDOWN_SUSPEND); +} + static int xen_suspend(void *__unused) { - int err; + int err, old_state; daemonize("suspend"); err = set_cpus_allowed(current, cpumask_of_cpu(0)); if (err) { printk(KERN_ERR "Xen suspend can't run on CPU0 (%d)\n", err); - goto out; - } - - err = __xen_suspend(fast_suspend); - if (err) - printk(KERN_ERR "Xen suspend failed (%d)\n", err); - - out: - shutting_down = SHUTDOWN_INVALID; + goto fail; + } + + do { + err = __xen_suspend(fast_suspend, xen_resume_notifier); + if (err) { + printk(KERN_ERR "Xen suspend failed (%d)\n", err); + goto fail; + } + old_state = cmpxchg( + &shutting_down, SHUTDOWN_RESUMING, SHUTDOWN_INVALID); + } while (old_state == SHUTDOWN_SUSPEND); + + switch (old_state) { + case SHUTDOWN_INVALID: + case SHUTDOWN_SUSPEND: + BUG(); + case SHUTDOWN_RESUMING: + break; + default: + schedule_work(&shutdown_work); + break; + } + + return 0; + + fail: + old_state = xchg(&shutting_down, SHUTDOWN_INVALID); + BUG_ON(old_state != SHUTDOWN_SUSPEND); return 0; } @@ -106,9 +128,10 @@ static void shutdown_handler(struct xenb extern void ctrl_alt_del(void); char *str; struct xenbus_transaction xbt; - int err; - - if (shutting_down != SHUTDOWN_INVALID) + int err, old_state, new_state = SHUTDOWN_INVALID; + + if ((shutting_down != SHUTDOWN_INVALID) && + (shutting_down != SHUTDOWN_RESUMING)) return; again: @@ -132,20 +155,23 @@ static void shutdown_handler(struct xenb } if (strcmp(str, "poweroff") == 0) - shutting_down = SHUTDOWN_POWEROFF; + new_state = SHUTDOWN_POWEROFF; else if (strcmp(str, "reboot") == 0) ctrl_alt_del(); else if (strcmp(str, "suspend") == 0) - shutting_down = SHUTDOWN_SUSPEND; + new_state = SHUTDOWN_SUSPEND; else if (strcmp(str, "halt") == 0) - shutting_down = SHUTDOWN_HALT; - else { + new_state = SHUTDOWN_HALT; + else printk("Ignoring shutdown request: %s\n", str); - shutting_down = SHUTDOWN_INVALID; - } - - if (shutting_down != SHUTDOWN_INVALID) - schedule_work(&shutdown_work); + + 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); + } kfree(str); } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog |
Lists.xenproject.org is hosted with RackSpace, monitoring our |