# 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
|