[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.