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
|