# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1204363768 0
# Node ID 53fadc573530c74ec14a7ddc48499971189f0cb2
# Parent 69b8e7e848857ad9434b9c088a03191a11b83fd7
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>
linux-2.6.18-xen changeset: 451:49ffe9ef67d420bde98e7ead29c9b9bfc5b026ba
linux-2.6.18-xen date: Fri Feb 29 10:29:13 2008 +0000
---
linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c | 25 +++--
linux-2.6-xen-sparse/drivers/xen/core/reboot.c | 82 +++++++++++------
2 files changed, 70 insertions(+), 37 deletions(-)
diff -r 69b8e7e84885 -r 53fadc573530
linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Sat Mar 01
09:28:59 2008 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Sat Mar 01
09:29:28 2008 +0000
@@ -128,13 +128,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());
@@ -167,6 +172,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) {
@@ -177,7 +183,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(
@@ -189,15 +195,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());
@@ -216,11 +223,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 69b8e7e84885 -r 53fadc573530
linux-2.6-xen-sparse/drivers/xen/core/reboot.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/reboot.c Sat Mar 01 09:28:59
2008 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/core/reboot.c Sat Mar 01 09:29:28
2008 +0000
@@ -17,11 +17,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. */
@@ -33,7 +29,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)
{
@@ -62,23 +58,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;
}
@@ -103,9 +125,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:
@@ -129,20 +152,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
|