[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, ¶m); + + 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |