[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 2 of 4 RFC] xen, pod: Check zero-check pages returned by the balloon driver
When a gfn is passed back by the balloon driver to Xen, check to see if it's in a superpage; and if so, check to see if that page is zeroed, and if so reclaim it. This patch significantly reduces superpage fragmentation when running on a high number of vcpus and significant memory ballooning. Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -74,6 +74,7 @@ boolean_param("hap_2mb", opt_hap_2mb); #define SUPERPAGE_PAGES (1UL << 9) #define superpage_aligned(_x) (((_x)&(SUPERPAGE_PAGES-1))==0) +#define order_aligned(_x,_o) (((_x)&((1<<(_o))-1))==0) static unsigned long p2m_type_to_flags(p2m_type_t t, mfn_t mfn) { @@ -767,6 +768,9 @@ p2m_pod_offline_or_broken_replace(struct return; } +static int p2m_pod_zero_check_superpage(struct p2m_domain *p2m, unsigned long gfn); + + /* This function is needed for two reasons: * + To properly handle clearing of PoD entries * + To "steal back" memory being freed for the PoD cache, rather than @@ -774,6 +778,9 @@ p2m_pod_offline_or_broken_replace(struct * * Once both of these functions have been completed, we can return and * allow decrease_reservation() to handle everything else. + * + * Because the balloon driver races with the page scrubber, we also + * scan for zeroed superpages we can reclaim. */ int p2m_pod_decrease_reservation(struct domain *d, @@ -781,11 +788,16 @@ p2m_pod_decrease_reservation(struct doma unsigned int order) { int ret=0; - int i; + int i, entry_size=0; struct p2m_domain *p2m = p2m_get_hostp2m(d); int steal_for_cache = 0; - int pod = 0, nonpod = 0, ram = 0; + int nonpod = 0; +#if 0 + unsigned long gfn_aligned; + + int nonpod = 0, ram = 0; +#endif /* If we don't have any outstanding PoD entries, let things take their @@ -794,7 +806,8 @@ p2m_pod_decrease_reservation(struct doma goto out; /* Figure out if we need to steal some freed memory for our cache */ - steal_for_cache = ( p2m->pod.entry_count > p2m->pod.count ); + if ( p2m->pod.entry_count > p2m->pod.count ) + steal_for_cache = ( p2m->pod.entry_count - p2m->pod.count ); p2m_lock(p2m); audit_p2m(p2m, 1); @@ -802,7 +815,7 @@ p2m_pod_decrease_reservation(struct doma if ( unlikely(d->is_dying) ) goto out_unlock; - /* See what's in here. */ +#if 0 /* FIXME: Add contiguous; query for PSE entries? */ for ( i=0; i<(1<<order); i++) { @@ -876,12 +889,105 @@ p2m_pod_decrease_reservation(struct doma } } +#else +/* + * while(more pages to look at) + * - Find the next page unit + * - if req_decrease >= page_size + * or page is zero + * - Reclaim whole page + * - else + * - Reclaim req_decrease + * - break out of the loop + */ + /* FIXME: Add contiguous; query for PSE entries? */ + for ( i=0; i<(1<<order); i+=entry_size) + { + mfn_t mfn; + p2m_type_t t; + p2m_access_t a; + int l, entry_order; + + /* See what's in here. */ + mfn = p2m->get_entry(p2m, gpfn + i, &t, &a, &l, p2m_query); + + /* NB: entry_size is used by the loop update; so if you change the + * level at which you're working (i.e., decide to work w/ 4k + * pages instead of a superpage), you must change entry_size + * so that the loop logic works right. */ + entry_order = (l-1)*9; + entry_size = 1<<(entry_order); + + /* If this is in a superpage and we need ram, try to nab it */ + if ( steal_for_cache + && entry_order == 9 + && p2m_is_ram(t) + && p2m_pod_zero_check_superpage(p2m, gpfn & ~(SUPERPAGE_PAGES-1)) ) + { + /* Now we have a PoD entry to deal with; update + * steal_for_cache, and set entry_size to 0 so that we + * re-process the entry. */ + entry_size=0; + + /* Update steal_for_cache */ + if ( p2m->pod.entry_count > p2m->pod.count ) + steal_for_cache = ( p2m->pod.entry_count - p2m->pod.count ); + else + steal_for_cache = 0; + + continue; + } + + /* Switch to singleton pages if we don't want to reclaim the + * whole page, or if the start is not SP aligned. Future + * iterations to this superpage frame will then be */ + if ( entry_order > 0 + && ( i + entry_size > (1<<order) + || !superpage_aligned(gpfn + i) ) ) + { + entry_order = 0; + entry_size = 1; + } + + if ( t == p2m_populate_on_demand ) + { + set_p2m_entry(p2m, gpfn+i, _mfn(INVALID_MFN), entry_order, p2m_invalid, p2m->default_access); + p2m->pod.entry_count-=(1<<entry_order); /* Lock: p2m */ + BUG_ON(p2m->pod.entry_count < 0); + } + else if( p2m_is_ram(t) ) + { + if ( steal_for_cache ) + { + struct page_info *page; + + ASSERT(mfn_valid(mfn)); + + page = mfn_to_page(mfn); + + set_p2m_entry(p2m, gpfn + i, _mfn(INVALID_MFN), entry_order, + p2m_invalid, p2m->default_access); + set_gpfn_from_mfn(mfn_x(mfn), INVALID_M2P_ENTRY); + + p2m_pod_cache_add(p2m, page, entry_order); + + /* Update steal_for_cache */ + if ( p2m->pod.entry_count > p2m->pod.count ) + steal_for_cache = ( p2m->pod.entry_count - p2m->pod.count ); + else + steal_for_cache = 0; + } + else + nonpod++; + } + } +#endif /* If there are no more non-PoD entries, tell decrease_reservation() that * there's nothing left to do. */ if ( nonpod == 0 ) ret = 1; -out_entry_check: +//out_entry_check: /* If we've reduced our "liabilities" beyond our "assets", free some */ if ( p2m->pod.entry_count < p2m->pod.count ) { @@ -1040,6 +1146,8 @@ p2m_pod_zero_check_superpage(struct p2m_ p2m_pod_cache_add(p2m, mfn_to_page(mfn0), 9); p2m->pod.entry_count += SUPERPAGE_PAGES; + ret = SUPERPAGE_PAGES; + out_reset: if ( reset ) set_p2m_entry(p2m, gfn, mfn0, 9, type0, p2m->default_access); _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |