[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] serialize suspend-resume process



Hi,


With current suspend-resume code, there is no way for DOM-0 to identify that DOM-U resume is completed. It can potentially trigger suspend again before resume is completed.

Below patch makes suspend-resume process serialized.


regards,
--
bvk-chaitanya
suspend-resume process is serialized.

Under heavy load a suspend interrupt can create a new kthread and
start suspend process before old kthread's resuming completes.  This
patch serialzes suspend-resume using a counting semaphore and a
separate kthread.  Suspend interrupts up the semaphore and suspend
kthread downs the semaphore in a while(1) loop.

diff -r c2850a7f279d drivers/xen/core/reboot.c
--- a/drivers/xen/core/reboot.c Wed Jul 30 20:15:23 2008 +0530
+++ b/drivers/xen/core/reboot.c Thu Jul 31 21:35:46 2008 +0530
@@ -11,6 +11,7 @@
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/kthread.h>
 
 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
 #include <xen/platform-compat.h>
@@ -20,8 +21,6 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 #define SHUTDOWN_INVALID  -1
 #define SHUTDOWN_POWEROFF  0
-#define SHUTDOWN_SUSPEND   2
-#define SHUTDOWN_RESUMING  3
 #define SHUTDOWN_HALT      4
 
 /* Ignore multiple shutdown requests. */
@@ -32,6 +31,11 @@ static int fast_suspend;
 
 static void __shutdown_handler(void *unused);
 static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
+
+static struct suspend_info {
+        struct semaphore nrequest; /* no. of suspend reqs */
+        atomic_t         resuming; /* is domain resuming ? */
+} suspend_info;
 
 int __xen_suspend(int fast_suspend, void (*resume_notifier)(void));
 
@@ -62,58 +66,11 @@ 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, 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 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;
-}
-
 static void __shutdown_handler(void *unused)
 {
        int err;
 
-       err = kernel_thread((shutting_down == SHUTDOWN_SUSPEND) ?
-                           xen_suspend : shutdown_process,
+       err = kernel_thread(shutdown_process,
                            NULL, CLONE_FS | CLONE_FILES);
 
        if (err < 0) {
@@ -131,8 +88,8 @@ static void shutdown_handler(struct xenb
        struct xenbus_transaction xbt;
        int err, old_state, new_state = SHUTDOWN_INVALID;
 
-       if ((shutting_down != SHUTDOWN_INVALID) &&
-           (shutting_down != SHUTDOWN_RESUMING))
+       if ((shutting_down != SHUTDOWN_INVALID) ||
+            atomic_read(&suspend_info.resuming))
                return;
 
  again:
@@ -155,12 +112,12 @@ static void shutdown_handler(struct xenb
                goto again;
        }
 
-       if (strcmp(str, "poweroff") == 0)
-               new_state = SHUTDOWN_POWEROFF;
+        if (strcmp(str, "suspend") == 0)
+                up(&suspend_info.nrequest); /* backward compatibility */
        else if (strcmp(str, "reboot") == 0)
                ctrl_alt_del();
-       else if (strcmp(str, "suspend") == 0)
-               new_state = SHUTDOWN_SUSPEND;
+       else if (strcmp(str, "poweroff") == 0)
+               new_state = SHUTDOWN_POWEROFF;
        else if (strcmp(str, "halt") == 0)
                new_state = SHUTDOWN_HALT;
        else
@@ -168,10 +125,8 @@ static void shutdown_handler(struct xenb
 
        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);
+                BUG_ON(old_state != SHUTDOWN_INVALID);
+                schedule_work(&shutdown_work);
        }
 
        kfree(str);
@@ -218,10 +173,41 @@ static struct xenbus_watch sysrq_watch =
        .callback = sysrq_handler
 };
 
+static void suspend_resume_notifier(void)
+{
+        atomic_set(&suspend_info.resuming, 1);
+        return;
+}
+
+static int suspend_machine(void *unused)
+{
+        int err = 0;
+        struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+
+        err = set_cpus_allowed(current, cpumask_of_cpu(0));
+        if (err) {
+                printk(KERN_ERR "Suspend thread couldn't switch to CPU0 
(%d)\n", err);
+                return err;
+        }
+
+        sched_setscheduler(current, SCHED_FIFO, &param);
+
+        while (1) {
+                /* decrement no. of suspend requests */
+                down(&suspend_info.nrequest);
+
+                err = __xen_suspend(fast_suspend, &suspend_resume_notifier);
+                if (err)
+                        printk(KERN_ERR "Domain suspend failed (%d)\n", err);
+
+                atomic_set(&suspend_info.resuming, 0);
+        }
+}
+
 static irqreturn_t suspend_int(int irq, void* dev_id, struct pt_regs *ptregs)
 {
-       shutting_down = SHUTDOWN_SUSPEND;
-       schedule_work(&shutdown_work);
+        /* increment no. of suspend requests */
+        up(&suspend_info.nrequest);
 
        return IRQ_HANDLED;
 }
@@ -251,6 +237,7 @@ static int setup_shutdown_watcher(void)
 static int setup_shutdown_watcher(void)
 {
        int err;
+        struct task_struct *t = NULL;
 
        xenbus_scanf(XBT_NIL, "control",
                     "platform-feature-multiprocessor-suspend",
@@ -267,6 +254,15 @@ static int setup_shutdown_watcher(void)
                printk(KERN_ERR "Failed to set sysrq watcher\n");
                return err;
        }
+
+        sema_init(&suspend_info.nrequest, 0);
+        atomic_set(&suspend_info.resuming, 0);
+        t = kthread_create(suspend_machine, &suspend_info, "ksuspend");
+        if (IS_ERR(t)) {
+                printk(KERN_ERR "Suspend thread creation failed\n");
+                return PTR_ERR(t);
+        }
+        wake_up_process(t);
 
        /* suspend event channel */
        err = setup_suspend_evtchn();
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

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