From: Keir Fraser Date: Fri, 11 Dec 2009 08:42:28 +0000 (+0000) Subject: PoD: appropriate BUG_ON when domain is dying X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~12936 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ef9550e2e2f3d682155f9c236c94c254f3369686;p=xen.git 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 Acked-by: George Dunlap --- diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 976b84c200..2e8794c688 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -267,6 +267,8 @@ p2m_pod_cache_add(struct domain *d, } #endif + ASSERT(p2m_locked_by_me(p2md)); + /* * Pages from domain_alloc and returned by the balloon driver aren't * guaranteed to be zero; but by reclaiming zero pages, we implicitly @@ -303,7 +305,9 @@ p2m_pod_cache_add(struct domain *d, BUG(); } - BUG_ON(d->is_dying); + /* Ensure that the PoD cache has never been emptied. + * This may cause "zombie domains" since the page will never be freed. */ + BUG_ON( d->arch.relmem != RELMEM_not_started ); spin_unlock(&d->page_alloc_lock); @@ -501,6 +505,8 @@ p2m_pod_set_mem_target(struct domain *d, unsigned long target) int ret = 0; unsigned long populated; + p2m_lock(p2md); + /* P == B: Nothing to do. */ if ( p2md->pod.entry_count == 0 ) goto out; @@ -528,6 +534,8 @@ p2m_pod_set_mem_target(struct domain *d, unsigned long target) ret = p2m_pod_set_cache_target(d, pod_target); out: + p2m_unlock(p2md); + return ret; } @@ -537,6 +545,10 @@ p2m_pod_empty_cache(struct domain *d) struct p2m_domain *p2md = d->arch.p2m; struct page_info *page; + /* After this barrier no new PoD activities can happen. */ + BUG_ON(!d->is_dying); + spin_barrier(&p2md->lock); + spin_lock(&d->page_alloc_lock); while ( (page = page_list_remove_head(&p2md->pod.super)) ) @@ -588,7 +600,7 @@ p2m_pod_decrease_reservation(struct domain *d, /* If we don't have any outstanding PoD entries, let things take their * course */ - if ( p2md->pod.entry_count == 0 || unlikely(d->is_dying) ) + if ( p2md->pod.entry_count == 0 ) goto out; /* Figure out if we need to steal some freed memory for our cache */ @@ -597,6 +609,9 @@ p2m_pod_decrease_reservation(struct domain *d, p2m_lock(p2md); audit_p2m(d); + if ( unlikely(d->is_dying) ) + goto out_unlock; + /* See what's in here. */ /* FIXME: Add contiguous; query for PSE entries? */ for ( i=0; i<(1<arch.p2m; int i; + ASSERT(p2m_locked_by_me(d->arch.p2m)); + /* This check is done with the p2m lock held. This will make sure that - * even if d->is_dying changes under our feet, empty_pod_cache() won't start - * until we're done. */ + * even if d->is_dying changes under our feet, p2m_pod_empty_cache() + * won't start until we're done. */ if ( unlikely(d->is_dying) ) goto out_fail;