ia64/linux-2.6.18-xen.hg

changeset 456:49ffe9ef67d4

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@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Feb 29 10:29:13 2008 +0000 (2008-02-29)
parents 87721beab1b9
children 68e78169679e
files drivers/xen/core/machine_reboot.c drivers/xen/core/reboot.c
line diff
     1.1 --- a/drivers/xen/core/machine_reboot.c	Thu Feb 28 16:41:41 2008 +0000
     1.2 +++ b/drivers/xen/core/machine_reboot.c	Fri Feb 29 10:29:13 2008 +0000
     1.3 @@ -129,13 +129,18 @@ static void post_suspend(int suspend_can
     1.4  
     1.5  #endif
     1.6  
     1.7 -static int take_machine_down(void *p_fast_suspend)
     1.8 +struct suspend {
     1.9 +	int fast_suspend;
    1.10 +	void (*resume_notifier)(void);
    1.11 +};
    1.12 +
    1.13 +static int take_machine_down(void *_suspend)
    1.14  {
    1.15 -	int fast_suspend = *(int *)p_fast_suspend;
    1.16 +	struct suspend *suspend = _suspend;
    1.17  	int suspend_cancelled, err;
    1.18  	extern void time_resume(void);
    1.19  
    1.20 -	if (fast_suspend) {
    1.21 +	if (suspend->fast_suspend) {
    1.22  		BUG_ON(!irqs_disabled());
    1.23  	} else {
    1.24  		BUG_ON(irqs_disabled());
    1.25 @@ -168,6 +173,7 @@ static int take_machine_down(void *p_fas
    1.26  	 */
    1.27  	suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
    1.28  
    1.29 +	suspend->resume_notifier();
    1.30  	post_suspend(suspend_cancelled);
    1.31  	gnttab_resume();
    1.32  	if (!suspend_cancelled) {
    1.33 @@ -178,7 +184,7 @@ static int take_machine_down(void *p_fas
    1.34  		 * We do it here just in case, but there's no need if we are
    1.35  		 * in fast-suspend mode as that implies a new enough Xen.
    1.36  		 */
    1.37 -		if (!fast_suspend) {
    1.38 +		if (!suspend->fast_suspend) {
    1.39  			struct mmuext_op op;
    1.40  			op.cmd = MMUEXT_NEW_USER_BASEPTR;
    1.41  			op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd(
    1.42 @@ -190,15 +196,16 @@ static int take_machine_down(void *p_fas
    1.43  	}
    1.44  	time_resume();
    1.45  
    1.46 -	if (!fast_suspend)
    1.47 +	if (!suspend->fast_suspend)
    1.48  		local_irq_enable();
    1.49  
    1.50  	return suspend_cancelled;
    1.51  }
    1.52  
    1.53 -int __xen_suspend(int fast_suspend)
    1.54 +int __xen_suspend(int fast_suspend, void (*resume_notifier)(void))
    1.55  {
    1.56  	int err, suspend_cancelled;
    1.57 +	struct suspend suspend = { fast_suspend, resume_notifier };
    1.58  
    1.59  	BUG_ON(smp_processor_id() != 0);
    1.60  	BUG_ON(in_interrupt());
    1.61 @@ -217,11 +224,11 @@ int __xen_suspend(int fast_suspend)
    1.62  
    1.63  	if (fast_suspend) {
    1.64  		xenbus_suspend();
    1.65 -		err = stop_machine_run(take_machine_down, &fast_suspend, 0);
    1.66 +		err = stop_machine_run(take_machine_down, &suspend, 0);
    1.67  		if (err < 0)
    1.68  			xenbus_suspend_cancel();
    1.69  	} else {
    1.70 -		err = take_machine_down(&fast_suspend);
    1.71 +		err = take_machine_down(&suspend);
    1.72  	}
    1.73  
    1.74  	if (err < 0)
     2.1 --- a/drivers/xen/core/reboot.c	Thu Feb 28 16:41:41 2008 +0000
     2.2 +++ b/drivers/xen/core/reboot.c	Fri Feb 29 10:29:13 2008 +0000
     2.3 @@ -20,11 +20,7 @@ MODULE_LICENSE("Dual BSD/GPL");
     2.4  #define SHUTDOWN_INVALID  -1
     2.5  #define SHUTDOWN_POWEROFF  0
     2.6  #define SHUTDOWN_SUSPEND   2
     2.7 -/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
     2.8 - * report a crash, not be instructed to crash!
     2.9 - * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
    2.10 - * the distinction when we return the reason code to them.
    2.11 - */
    2.12 +#define SHUTDOWN_RESUMING  3
    2.13  #define SHUTDOWN_HALT      4
    2.14  
    2.15  /* Ignore multiple shutdown requests. */
    2.16 @@ -36,7 +32,7 @@ static int fast_suspend;
    2.17  static void __shutdown_handler(void *unused);
    2.18  static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
    2.19  
    2.20 -int __xen_suspend(int fast_suspend);
    2.21 +int __xen_suspend(int fast_suspend, void (*resume_notifier)(void));
    2.22  
    2.23  static int shutdown_process(void *__unused)
    2.24  {
    2.25 @@ -65,23 +61,49 @@ static int shutdown_process(void *__unus
    2.26  	return 0;
    2.27  }
    2.28  
    2.29 +static void xen_resume_notifier(void)
    2.30 +{
    2.31 +	int old_state = xchg(&shutting_down, SHUTDOWN_RESUMING);
    2.32 +	BUG_ON(old_state != SHUTDOWN_SUSPEND);
    2.33 +}
    2.34 +
    2.35  static int xen_suspend(void *__unused)
    2.36  {
    2.37 -	int err;
    2.38 +	int err, old_state;
    2.39  
    2.40  	daemonize("suspend");
    2.41  	err = set_cpus_allowed(current, cpumask_of_cpu(0));
    2.42  	if (err) {
    2.43  		printk(KERN_ERR "Xen suspend can't run on CPU0 (%d)\n", err);
    2.44 -		goto out;
    2.45 +		goto fail;
    2.46  	}
    2.47  
    2.48 -	err = __xen_suspend(fast_suspend);
    2.49 -	if (err)
    2.50 -		printk(KERN_ERR "Xen suspend failed (%d)\n", err);
    2.51 +	do {
    2.52 +		err = __xen_suspend(fast_suspend, xen_resume_notifier);
    2.53 +		if (err) {
    2.54 +			printk(KERN_ERR "Xen suspend failed (%d)\n", err);
    2.55 +			goto fail;
    2.56 +		}
    2.57 +		old_state = cmpxchg(
    2.58 +			&shutting_down, SHUTDOWN_RESUMING, SHUTDOWN_INVALID);
    2.59 +	} while (old_state == SHUTDOWN_SUSPEND);
    2.60  
    2.61 - out:
    2.62 -	shutting_down = SHUTDOWN_INVALID;
    2.63 +	switch (old_state) {
    2.64 +	case SHUTDOWN_INVALID:
    2.65 +	case SHUTDOWN_SUSPEND:
    2.66 +		BUG();
    2.67 +	case SHUTDOWN_RESUMING:
    2.68 +		break;
    2.69 +	default:
    2.70 +		schedule_work(&shutdown_work);
    2.71 +		break;
    2.72 +	}
    2.73 +
    2.74 +	return 0;
    2.75 +
    2.76 + fail:
    2.77 +	old_state = xchg(&shutting_down, SHUTDOWN_INVALID);
    2.78 +	BUG_ON(old_state != SHUTDOWN_SUSPEND);
    2.79  	return 0;
    2.80  }
    2.81  
    2.82 @@ -106,9 +128,10 @@ static void shutdown_handler(struct xenb
    2.83  	extern void ctrl_alt_del(void);
    2.84  	char *str;
    2.85  	struct xenbus_transaction xbt;
    2.86 -	int err;
    2.87 +	int err, old_state, new_state = SHUTDOWN_INVALID;
    2.88  
    2.89 -	if (shutting_down != SHUTDOWN_INVALID)
    2.90 +	if ((shutting_down != SHUTDOWN_INVALID) &&
    2.91 +	    (shutting_down != SHUTDOWN_RESUMING))
    2.92  		return;
    2.93  
    2.94   again:
    2.95 @@ -132,21 +155,24 @@ static void shutdown_handler(struct xenb
    2.96  	}
    2.97  
    2.98  	if (strcmp(str, "poweroff") == 0)
    2.99 -		shutting_down = SHUTDOWN_POWEROFF;
   2.100 +		new_state = SHUTDOWN_POWEROFF;
   2.101  	else if (strcmp(str, "reboot") == 0)
   2.102  		ctrl_alt_del();
   2.103  	else if (strcmp(str, "suspend") == 0)
   2.104 -		shutting_down = SHUTDOWN_SUSPEND;
   2.105 +		new_state = SHUTDOWN_SUSPEND;
   2.106  	else if (strcmp(str, "halt") == 0)
   2.107 -		shutting_down = SHUTDOWN_HALT;
   2.108 -	else {
   2.109 +		new_state = SHUTDOWN_HALT;
   2.110 +	else
   2.111  		printk("Ignoring shutdown request: %s\n", str);
   2.112 -		shutting_down = SHUTDOWN_INVALID;
   2.113 +
   2.114 +	if (new_state != SHUTDOWN_INVALID) {
   2.115 +		old_state = xchg(&shutting_down, new_state);
   2.116 +		if (old_state == SHUTDOWN_INVALID)
   2.117 +			schedule_work(&shutdown_work);
   2.118 +		else
   2.119 +			BUG_ON(old_state != SHUTDOWN_RESUMING);
   2.120  	}
   2.121  
   2.122 -	if (shutting_down != SHUTDOWN_INVALID)
   2.123 -		schedule_work(&shutdown_work);
   2.124 -
   2.125  	kfree(str);
   2.126  }
   2.127