debuggers.hg

changeset 21226:11423ce78ee0

acpi sleep: Rearrange code for entering system sleep states.

We cannot freeze_domains in hypercall-continuation context any more,
since that is a softirq context which can interrupt an arbitrary
vcpu. Hence sleeping all vcpus in that context can easily deadlock
(against the vcpu we interrupted). So rearrange the code to
freeze_domains before calling continue_hypercall_on_cpu().

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Apr 15 11:36:20 2010 +0100 (2010-04-15)
parents 85ab727868ea
children 9d5ecf79f1b5
files xen/arch/x86/acpi/power.c
line diff
     1.1 --- a/xen/arch/x86/acpi/power.c	Thu Apr 15 11:33:39 2010 +0100
     1.2 +++ b/xen/arch/x86/acpi/power.c	Thu Apr 15 11:36:20 2010 +0100
     1.3 @@ -149,15 +149,7 @@ static int enter_state(u32 state)
     1.4      int error;
     1.5      unsigned long cr4;
     1.6  
     1.7 -    if ( (state <= ACPI_STATE_S0) || (state > ACPI_S_STATES_MAX) )
     1.8 -        return -EINVAL;
     1.9 -
    1.10 -    if ( !spin_trylock(&pm_lock) )
    1.11 -        return -EBUSY;
    1.12 -
    1.13 -    printk(XENLOG_INFO "Preparing system for ACPI S%d state.", state);
    1.14 -
    1.15 -    freeze_domains();
    1.16 +    BUG_ON(!spin_is_locked(&pm_lock));
    1.17  
    1.18      disable_nonboot_cpus();
    1.19      if ( num_online_cpus() != 1 )
    1.20 @@ -246,6 +238,9 @@ static long enter_state_helper(void *dat
    1.21   */
    1.22  int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep)
    1.23  {
    1.24 +    int rc;
    1.25 +    u32 state;
    1.26 +
    1.27      if ( !IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt_blk.address )
    1.28          return -EPERM;
    1.29  
    1.30 @@ -258,14 +253,31 @@ int acpi_enter_sleep(struct xenpf_enter_
    1.31          return -EINVAL;
    1.32      }
    1.33  
    1.34 -    if ( sleep->flags )
    1.35 +    state = sleep->sleep_state;
    1.36 +    if ( sleep->flags ||
    1.37 +         (state <= ACPI_STATE_S0) || (state > ACPI_S_STATES_MAX) )
    1.38          return -EINVAL;
    1.39  
    1.40 +    if ( !spin_trylock(&pm_lock) )
    1.41 +        return -EBUSY;
    1.42 +
    1.43      acpi_sinfo.pm1a_cnt_val = sleep->pm1a_cnt_val;
    1.44      acpi_sinfo.pm1b_cnt_val = sleep->pm1b_cnt_val;
    1.45 -    acpi_sinfo.sleep_state = sleep->sleep_state;
    1.46 +    acpi_sinfo.sleep_state = state;
    1.47 +
    1.48 +    printk(XENLOG_INFO "Preparing system for ACPI S%d state.", state);
    1.49 +
    1.50 +    freeze_domains();
    1.51  
    1.52 -    return continue_hypercall_on_cpu(0, enter_state_helper, &acpi_sinfo);
    1.53 +    rc = continue_hypercall_on_cpu(0, enter_state_helper, &acpi_sinfo);
    1.54 +    if ( rc )
    1.55 +    {
    1.56 +        /* Continuation will not execute: undo our own work so far. */
    1.57 +        thaw_domains();
    1.58 +        spin_unlock(&pm_lock);
    1.59 +    }
    1.60 +
    1.61 +    return rc;
    1.62  }
    1.63  
    1.64  static int acpi_get_wake_status(void)