debuggers.hg

changeset 20652:295e77eed8c9

PoD: appropriate BUG_ON when domain is dying

BUG_ON(d->is_dying) in p2m_pod_cache_add() which is introduced in
c/s 20426 is not proper. Since dom->is_dying is set asynchronously.
For example, MMU_UPDATE hypercalls from qemu and the
DOMCTL_destroydomain hypercall from xend can be issued simultaneously.

Also this patch lets p2m_pod_empty_cache() wait by spin_barrier
until another PoD operation ceases.

Signed-off-by: Kouya Shimura <kouya@jp.fujitsu.com>
Acked-by: George Dunlap <george.dunlap@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Dec 11 08:42:28 2009 +0000 (2009-12-11)
parents 8f304c003af4
children 5f076dbdab6c
files xen/arch/x86/mm/p2m.c
line diff
     1.1 --- a/xen/arch/x86/mm/p2m.c	Wed Dec 09 10:59:31 2009 +0000
     1.2 +++ b/xen/arch/x86/mm/p2m.c	Fri Dec 11 08:42:28 2009 +0000
     1.3 @@ -267,6 +267,8 @@ p2m_pod_cache_add(struct domain *d,
     1.4      }
     1.5  #endif
     1.6  
     1.7 +    ASSERT(p2m_locked_by_me(p2md));
     1.8 +
     1.9      /*
    1.10       * Pages from domain_alloc and returned by the balloon driver aren't
    1.11       * guaranteed to be zero; but by reclaiming zero pages, we implicitly
    1.12 @@ -303,7 +305,9 @@ p2m_pod_cache_add(struct domain *d,
    1.13          BUG();
    1.14      }
    1.15  
    1.16 -    BUG_ON(d->is_dying);
    1.17 +    /* Ensure that the PoD cache has never been emptied.  
    1.18 +     * This may cause "zombie domains" since the page will never be freed. */
    1.19 +    BUG_ON( d->arch.relmem != RELMEM_not_started );
    1.20  
    1.21      spin_unlock(&d->page_alloc_lock);
    1.22  
    1.23 @@ -501,6 +505,8 @@ p2m_pod_set_mem_target(struct domain *d,
    1.24      int ret = 0;
    1.25      unsigned long populated;
    1.26  
    1.27 +    p2m_lock(p2md);
    1.28 +
    1.29      /* P == B: Nothing to do. */
    1.30      if ( p2md->pod.entry_count == 0 )
    1.31          goto out;
    1.32 @@ -528,6 +534,8 @@ p2m_pod_set_mem_target(struct domain *d,
    1.33      ret = p2m_pod_set_cache_target(d, pod_target);
    1.34  
    1.35  out:
    1.36 +    p2m_unlock(p2md);
    1.37 +
    1.38      return ret;
    1.39  }
    1.40  
    1.41 @@ -537,6 +545,10 @@ p2m_pod_empty_cache(struct domain *d)
    1.42      struct p2m_domain *p2md = d->arch.p2m;
    1.43      struct page_info *page;
    1.44  
    1.45 +    /* After this barrier no new PoD activities can happen. */
    1.46 +    BUG_ON(!d->is_dying);
    1.47 +    spin_barrier(&p2md->lock);
    1.48 +
    1.49      spin_lock(&d->page_alloc_lock);
    1.50  
    1.51      while ( (page = page_list_remove_head(&p2md->pod.super)) )
    1.52 @@ -588,7 +600,7 @@ p2m_pod_decrease_reservation(struct doma
    1.53  
    1.54      /* If we don't have any outstanding PoD entries, let things take their
    1.55       * course */
    1.56 -    if ( p2md->pod.entry_count == 0 || unlikely(d->is_dying) )
    1.57 +    if ( p2md->pod.entry_count == 0 )
    1.58          goto out;
    1.59  
    1.60      /* Figure out if we need to steal some freed memory for our cache */
    1.61 @@ -597,6 +609,9 @@ p2m_pod_decrease_reservation(struct doma
    1.62      p2m_lock(p2md);
    1.63      audit_p2m(d);
    1.64  
    1.65 +    if ( unlikely(d->is_dying) )
    1.66 +        goto out_unlock;
    1.67 +
    1.68      /* See what's in here. */
    1.69      /* FIXME: Add contiguous; query for PSE entries? */
    1.70      for ( i=0; i<(1<<order); i++)
    1.71 @@ -1006,9 +1021,11 @@ p2m_pod_demand_populate(struct domain *d
    1.72      struct p2m_domain *p2md = d->arch.p2m;
    1.73      int i;
    1.74  
    1.75 +    ASSERT(p2m_locked_by_me(d->arch.p2m));
    1.76 +
    1.77      /* This check is done with the p2m lock held.  This will make sure that
    1.78 -     * even if d->is_dying changes under our feet, empty_pod_cache() won't start
    1.79 -     * until we're done. */
    1.80 +     * even if d->is_dying changes under our feet, p2m_pod_empty_cache() 
    1.81 +     * won't start until we're done. */
    1.82      if ( unlikely(d->is_dying) )
    1.83          goto out_fail;
    1.84