ia64/xen-unstable

changeset 19522:3929487cdb82

Avoid deadlocks on domctl_lock when pausing domains/vcpus.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 08 13:48:35 2009 +0100 (2009-04-08)
parents 9f945f16bd02
children 2eed07698921
files xen/arch/x86/hvm/hvm.c xen/common/domctl.c xen/include/xen/domain.h xen/include/xen/hypercall.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Wed Apr 08 13:18:22 2009 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Wed Apr 08 13:48:35 2009 +0100
     1.3 @@ -2489,20 +2489,23 @@ long do_hvm_op(unsigned long op, XEN_GUE
     1.4                  if ( !paging_mode_hap(d) )
     1.5                      break;
     1.6  
     1.7 -                domain_pause(d);
     1.8 -
     1.9                  /*
    1.10                   * Update GUEST_CR3 in each VMCS to point at identity map.
    1.11                   * All foreign updates to guest state must synchronise on
    1.12                   * the domctl_lock.
    1.13                   */
    1.14 -                spin_lock(&domctl_lock);
    1.15 +                rc = -EAGAIN;
    1.16 +                if ( !domctl_lock_acquire() )
    1.17 +                    break;
    1.18 +
    1.19 +                rc = 0;
    1.20 +                domain_pause(d);
    1.21                  d->arch.hvm_domain.params[a.index] = a.value;
    1.22                  for_each_vcpu ( d, v )
    1.23                      paging_update_cr3(v);
    1.24 -                spin_unlock(&domctl_lock);
    1.25 -
    1.26                  domain_unpause(d);
    1.27 +
    1.28 +                domctl_lock_release();
    1.29                  break;
    1.30              case HVM_PARAM_DM_DOMAIN:
    1.31                  /* Privileged domains only, as we must domain_pause(d). */
     2.1 --- a/xen/common/domctl.c	Wed Apr 08 13:18:22 2009 +0100
     2.2 +++ b/xen/common/domctl.c	Wed Apr 08 13:48:35 2009 +0100
     2.3 @@ -25,7 +25,7 @@
     2.4  #include <public/domctl.h>
     2.5  #include <xsm/xsm.h>
     2.6  
     2.7 -DEFINE_SPINLOCK(domctl_lock);
     2.8 +static DEFINE_SPINLOCK(domctl_lock);
     2.9  
    2.10  extern long arch_do_domctl(
    2.11      struct xen_domctl *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl);
    2.12 @@ -188,6 +188,33 @@ static unsigned int default_vcpu0_locati
    2.13      return cpu;
    2.14  }
    2.15  
    2.16 +bool_t domctl_lock_acquire(void)
    2.17 +{
    2.18 +    /*
    2.19 +     * Caller may try to pause its own VCPUs. We must prevent deadlock
    2.20 +     * against other non-domctl routines which try to do the same.
    2.21 +     */
    2.22 +    if ( !spin_trylock(&current->domain->hypercall_deadlock_mutex) )
    2.23 +        return 0;
    2.24 +
    2.25 +    /*
    2.26 +     * Trylock here is paranoia if we have multiple privileged domains. Then
    2.27 +     * we could have one domain trying to pause another which is spinning
    2.28 +     * on domctl_lock -- results in deadlock.
    2.29 +     */
    2.30 +    if ( spin_trylock(&domctl_lock) )
    2.31 +        return 1;
    2.32 +
    2.33 +    spin_unlock(&current->domain->hypercall_deadlock_mutex);
    2.34 +    return 0;
    2.35 +}
    2.36 +
    2.37 +void domctl_lock_release(void)
    2.38 +{
    2.39 +    spin_unlock(&domctl_lock);
    2.40 +    spin_unlock(&current->domain->hypercall_deadlock_mutex);
    2.41 +}
    2.42 +
    2.43  long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
    2.44  {
    2.45      long ret = 0;
    2.46 @@ -202,7 +229,9 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
    2.47      if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION )
    2.48          return -EACCES;
    2.49  
    2.50 -    spin_lock(&domctl_lock);
    2.51 +    if ( !domctl_lock_acquire() )
    2.52 +        return hypercall_create_continuation(
    2.53 +            __HYPERVISOR_domctl, "h", u_domctl);
    2.54  
    2.55      switch ( op->cmd )
    2.56      {
    2.57 @@ -866,7 +895,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
    2.58          break;
    2.59      }
    2.60  
    2.61 -    spin_unlock(&domctl_lock);
    2.62 +    domctl_lock_release();
    2.63  
    2.64      return ret;
    2.65  }
     3.1 --- a/xen/include/xen/domain.h	Wed Apr 08 13:18:22 2009 +0100
     3.2 +++ b/xen/include/xen/domain.h	Wed Apr 08 13:48:35 2009 +0100
     3.3 @@ -58,6 +58,9 @@ void arch_dump_domain_info(struct domain
     3.4  
     3.5  void arch_vcpu_reset(struct vcpu *v);
     3.6  
     3.7 +bool_t domctl_lock_acquire(void);
     3.8 +void domctl_lock_release(void);
     3.9 +
    3.10  extern unsigned int xen_processor_pmbits;
    3.11  
    3.12  #endif /* __XEN_DOMAIN_H__ */
     4.1 --- a/xen/include/xen/hypercall.h	Wed Apr 08 13:18:22 2009 +0100
     4.2 +++ b/xen/include/xen/hypercall.h	Wed Apr 08 13:48:35 2009 +0100
     4.3 @@ -30,7 +30,6 @@ do_sched_op(
     4.4      int cmd,
     4.5      XEN_GUEST_HANDLE(void) arg);
     4.6  
     4.7 -extern spinlock_t domctl_lock;
     4.8  extern long
     4.9  do_domctl(
    4.10      XEN_GUEST_HANDLE(xen_domctl_t) u_domctl);