ia64/xen-unstable

changeset 6282:6e6cedc1763d

Make xm save/restore work for SMP guest domains.

Signed-off-by: Steven Smith, sos22@cam.ac.uk
author sos22@douglas.cl.cam.ac.uk
date Wed Aug 17 14:37:22 2005 +0000 (2005-08-17)
parents 69f00d6ab5dc
children 7f9b024a509e
files linux-2.6-xen-sparse/arch/xen/kernel/reboot.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c	Wed Aug 17 13:34:42 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c	Wed Aug 17 14:37:22 2005 +0000
     1.3 @@ -16,6 +16,8 @@
     1.4  #include <asm-xen/queues.h>
     1.5  #include <asm-xen/xenbus.h>
     1.6  #include <asm-xen/ctrl_if.h>
     1.7 +#include <linux/cpu.h>
     1.8 +#include <linux/kthread.h>
     1.9  
    1.10  #define SHUTDOWN_INVALID  -1
    1.11  #define SHUTDOWN_POWEROFF  0
    1.12 @@ -58,7 +60,12 @@ EXPORT_SYMBOL(machine_power_off);
    1.13  /* Ignore multiple shutdown requests. */
    1.14  static int shutting_down = SHUTDOWN_INVALID;
    1.15  
    1.16 -static void __do_suspend(void)
    1.17 +#ifndef CONFIG_HOTPLUG_CPU
    1.18 +#define cpu_down(x) (-EOPNOTSUPP)
    1.19 +#define cpu_up(x) (-EOPNOTSUPP)
    1.20 +#endif
    1.21 +
    1.22 +static int __do_suspend(void *ignore)
    1.23  {
    1.24      int i, j;
    1.25      suspend_record_t *suspend_record;
    1.26 @@ -104,10 +111,49 @@ static void __do_suspend(void)
    1.27      extern unsigned long max_pfn;
    1.28      extern unsigned int *pfn_to_mfn_frame_list;
    1.29  
    1.30 +    cpumask_t feasible_cpus;
    1.31 +    int err = 0;
    1.32 +
    1.33 +    BUG_ON(smp_processor_id() != 0);
    1.34 +    BUG_ON(in_interrupt());
    1.35 +
    1.36 +#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
    1.37 +    if (num_online_cpus() > 1) {
    1.38 +	printk(KERN_WARNING "Can't suspend SMP guests without CONFIG_HOTPLUG_CPU\n");
    1.39 +	return -EOPNOTSUPP;
    1.40 +    }
    1.41 +#endif
    1.42 +
    1.43      suspend_record = (suspend_record_t *)__get_free_page(GFP_KERNEL);
    1.44      if ( suspend_record == NULL )
    1.45          goto out;
    1.46  
    1.47 +    /* Take all of the other cpus offline.  We need to be careful not
    1.48 +       to get preempted between the final test for num_online_cpus()
    1.49 +       == 1 and disabling interrupts, since otherwise userspace could
    1.50 +       bring another cpu online, and then we'd be stuffed.  At the
    1.51 +       same time, cpu_down can reschedule, so we need to enable
    1.52 +       preemption while doing that.  This kind of sucks, but should be
    1.53 +       correct. */
    1.54 +    /* (We don't need to worry about other cpus bringing stuff up,
    1.55 +       since by the time num_online_cpus() == 1, there aren't any
    1.56 +       other cpus) */
    1.57 +    cpus_clear(feasible_cpus);
    1.58 +    preempt_disable();
    1.59 +    while (num_online_cpus() > 1) {
    1.60 +	preempt_enable();
    1.61 +	for_each_online_cpu(i) {
    1.62 +	    if (i == 0)
    1.63 +		continue;
    1.64 +	    err = cpu_down(i);
    1.65 +	    if (err != 0) {
    1.66 +		printk(KERN_CRIT "Failed to take all CPUs down: %d.\n", err);
    1.67 +		goto out_reenable_cpus;
    1.68 +	    }
    1.69 +	    cpu_set(i, feasible_cpus);
    1.70 +	}
    1.71 +    }
    1.72 +
    1.73      suspend_record->nr_pfns = max_pfn; /* final number of pfns */
    1.74  
    1.75      __cli();
    1.76 @@ -141,8 +187,11 @@ static void __do_suspend(void)
    1.77      memcpy(&suspend_record->resume_info, &xen_start_info,
    1.78             sizeof(xen_start_info));
    1.79  
    1.80 +    /* We'll stop somewhere inside this hypercall.  When it returns,
    1.81 +       we'll start resuming after the restore. */
    1.82      HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
    1.83  
    1.84 +
    1.85      shutting_down = SHUTDOWN_INVALID; 
    1.86  
    1.87      memcpy(&xen_start_info, &suspend_record->resume_info,
    1.88 @@ -182,11 +231,26 @@ static void __do_suspend(void)
    1.89  
    1.90      usbif_resume();
    1.91  
    1.92 +    preempt_enable();
    1.93 +
    1.94      __sti();
    1.95  
    1.96 + out_reenable_cpus:
    1.97 +    while (!cpus_empty(feasible_cpus)) {
    1.98 +	i = first_cpu(feasible_cpus);
    1.99 +	j = cpu_up(i);
   1.100 +	if (j != 0) {
   1.101 +	    printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n",
   1.102 +		   i, j);
   1.103 +	    err = j;
   1.104 +	}
   1.105 +	cpu_clear(i, feasible_cpus);
   1.106 +    }
   1.107 +
   1.108   out:
   1.109      if ( suspend_record != NULL )
   1.110          free_page((unsigned long)suspend_record);
   1.111 +    return err;
   1.112  }
   1.113  
   1.114  static int shutdown_process(void *__unused)
   1.115 @@ -233,6 +297,18 @@ static int shutdown_process(void *__unus
   1.116      return 0;
   1.117  }
   1.118  
   1.119 +static struct task_struct *kthread_create_on_cpu(int (*f)(void *arg),
   1.120 +						 void *arg,
   1.121 +						 const char *name,
   1.122 +						 int cpu)
   1.123 +{
   1.124 +    struct task_struct *p;
   1.125 +    p = kthread_create(f, arg, name);
   1.126 +    kthread_bind(p, cpu);
   1.127 +    wake_up_process(p);
   1.128 +    return p;
   1.129 +}
   1.130 +
   1.131  static void __shutdown_handler(void *unused)
   1.132  {
   1.133      int err;
   1.134 @@ -245,7 +321,7 @@ static void __shutdown_handler(void *unu
   1.135      }
   1.136      else
   1.137      {
   1.138 -        __do_suspend();
   1.139 +	kthread_create_on_cpu(__do_suspend, NULL, "suspender", 0);
   1.140      }
   1.141  }
   1.142