|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 2/4] xen: introduce an "scrub" free page list
Because of page scrubbing, it's very slow to destroy a domain with large memory.
It takes around 10 minutes when destroy a guest of nearly 1 TB of memory.
This patch introduced a "scrub" free page list, pages on this list need to be
scrubbed before use. During domain destory just mark pages "PGC_need_scrub"
and then add them to this list, so that xl can return quickly.
In alloc_domheap_pages():
- If there are pages on the normal "heap" freelist, allocate them.
- Try to allocate from the "scrub" free list with the same order and do
scrubbing synchronously.
In order to not fail high order allocate request, merge page trunks for
PGC_need_scrub pages.
Note: PCG_need_scrub pages and normal pages are not mergeable
Signed-off-by: Bob Liu <bob.liu@xxxxxxxxxx>
---
xen/common/page_alloc.c | 108 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 91 insertions(+), 17 deletions(-)
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 601319c..723d273 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -267,6 +267,9 @@ typedef struct page_list_head
heap_by_zone_and_order_t[NR_ZONES][MAX_ORDER+1];
static heap_by_zone_and_order_t *_heap[MAX_NUMNODES];
#define heap(node, zone, order) ((*_heap[node])[zone][order])
+static heap_by_zone_and_order_t _scrub[MAX_NUMNODES];
+#define scrub(node, zone, order) (_scrub[node][zone][order])
+
static unsigned long *avail[MAX_NUMNODES];
static long total_avail_pages;
@@ -629,8 +632,24 @@ static struct page_info *alloc_heap_pages(
/* Find smallest order which can satisfy the request. */
for ( j = order; j <= MAX_ORDER; j++ )
+ {
if ( (pg = page_list_remove_head(&heap(node, zone, j))) )
goto found;
+
+ /* Try to scrub a page directly */
+ if ( (pg = page_list_remove_head(&scrub(node, zone, j))) )
+ {
+ for ( i = 0; i < (1 << j); i++ )
+ {
+ if ( test_bit(_PGC_need_scrub, &(pg[i].count_info)) )
+ {
+ scrub_one_page(&pg[i]);
+ pg[i].count_info &= ~(PGC_need_scrub);
+ }
+ }
+ goto found;
+ }
+ }
} while ( zone-- > zone_lo ); /* careful: unsigned zone may wrap */
if ( memflags & MEMF_exact_node )
@@ -810,7 +829,7 @@ static int reserve_offlined_page(struct page_info *head)
/* Free 2^@order set of pages. */
static void free_heap_pages(
- struct page_info *pg, unsigned int order)
+ struct page_info *pg, unsigned int order, bool_t need_scrub)
{
unsigned long mask, mfn = page_to_mfn(pg);
unsigned int i, node = phys_to_nid(page_to_maddr(pg)), tainted = 0;
@@ -859,6 +878,22 @@ static void free_heap_pages(
midsize_alloc_zone_pages = max(
midsize_alloc_zone_pages, total_avail_pages / MIDSIZE_ALLOC_FRAC);
+ if ( need_scrub )
+ {
+ /* Specail for tainted case */
+ if ( tainted )
+ {
+ for ( i = 0; i < (1 << order); i++ )
+ scrub_one_page(&pg[i]);
+ need_scrub = 0;
+ }
+ else
+ {
+ for ( i = 0; i < (1 << order); i++ )
+ pg[i].count_info |= PGC_need_scrub;
+ }
+ }
+
/* Merge chunks as far as possible. */
while ( order < MAX_ORDER )
{
@@ -872,8 +907,22 @@ static void free_heap_pages(
(PFN_ORDER(pg-mask) != order) ||
(phys_to_nid(page_to_maddr(pg-mask)) != node) )
break;
- pg -= mask;
- page_list_del(pg, &heap(node, zone, order));
+
+ /* If we need scrub, only merge with PGC_need_scrub pages */
+ if ( need_scrub )
+ {
+ if ( !test_bit(_PGC_need_scrub, &((pg-mask)->count_info)) )
+ break;
+ pg -= mask;
+ page_list_del(pg, &scrub(node, zone, order));
+ }
+ else
+ {
+ if ( test_bit(_PGC_need_scrub, &((pg-mask)->count_info)) )
+ break;
+ pg -= mask;
+ page_list_del(pg, &heap(node, zone, order));
+ }
}
else
{
@@ -883,14 +932,35 @@ static void free_heap_pages(
(PFN_ORDER(pg+mask) != order) ||
(phys_to_nid(page_to_maddr(pg+mask)) != node) )
break;
- page_list_del(pg + mask, &heap(node, zone, order));
+
+ /* If we need scrub, only merge with PGC_need_scrub pages */
+ if ( need_scrub )
+ {
+ if ( !test_bit(_PGC_need_scrub, &((pg+mask)->count_info)) )
+ break;
+ page_list_del(pg + mask, &scrub(node, zone, order));
+ }
+ else
+ {
+ if ( test_bit(_PGC_need_scrub, &((pg+mask)->count_info)) )
+ break;
+ page_list_del(pg + mask, &heap(node, zone, order));
+ }
}
order++;
}
PFN_ORDER(pg) = order;
- page_list_add_tail(pg, &heap(node, zone, order));
+ if ( need_scrub )
+ {
+ ASSERT( test_bit(_PGC_need_scrub, &(pg->count_info)) );
+ page_list_add_tail(pg, &scrub(node, zone, order));
+ }
+ else
+ {
+ page_list_add_tail(pg, &heap(node, zone, order));
+ }
if ( tainted )
reserve_offlined_page(pg);
@@ -1115,7 +1185,7 @@ unsigned int online_page(unsigned long mfn, uint32_t
*status)
spin_unlock(&heap_lock);
if ( (y & PGC_state) == PGC_state_offlined )
- free_heap_pages(pg, 0);
+ free_heap_pages(pg, 0, 0);
return ret;
}
@@ -1184,7 +1254,7 @@ static void init_heap_pages(
nr_pages -= n;
}
- free_heap_pages(pg+i, 0);
+ free_heap_pages(pg+i, 0, 0);
}
}
@@ -1216,7 +1286,7 @@ unsigned long total_free_pages(void)
void __init end_boot_allocator(void)
{
- unsigned int i;
+ unsigned int i, j, order;
/* Pages that are free now go to the domain sub-allocator. */
for ( i = 0; i < nr_bootmem_regions; i++ )
@@ -1250,6 +1320,11 @@ void __init end_boot_allocator(void)
#endif
}
+ for ( i = 0; i < MAX_NUMNODES; i++ )
+ for ( j = 0; j < NR_ZONES; j++ )
+ for ( order = 0; order <= MAX_ORDER; order++ )
+ INIT_PAGE_LIST_HEAD(&scrub(i, j, order));
+
printk("Domain heap initialised");
if ( dma_bitsize )
printk(" DMA width %u bits", dma_bitsize);
@@ -1357,7 +1432,7 @@ void free_xenheap_pages(void *v, unsigned int order)
memguard_guard_range(v, 1 << (order + PAGE_SHIFT));
- free_heap_pages(virt_to_page(v), order);
+ free_heap_pages(virt_to_page(v), order, 0);
}
#else
@@ -1411,7 +1486,7 @@ void free_xenheap_pages(void *v, unsigned int order)
for ( i = 0; i < (1u << order); i++ )
pg[i].count_info &= ~PGC_xen_heap;
- free_heap_pages(pg, order);
+ free_heap_pages(pg, order, 0);
}
#endif
@@ -1515,7 +1590,7 @@ struct page_info *alloc_domheap_pages(
if ( (d != NULL) && assign_pages(d, pg, order, memflags) )
{
- free_heap_pages(pg, order);
+ free_heap_pages(pg, order, 0);
return NULL;
}
@@ -1564,22 +1639,21 @@ void free_domheap_pages(struct page_info *pg, unsigned
int order)
* domain has died we assume responsibility for erasure.
*/
if ( unlikely(d->is_dying) )
- for ( i = 0; i < (1 << order); i++ )
- scrub_one_page(&pg[i]);
-
- free_heap_pages(pg, order);
+ free_heap_pages(pg, order, 1);
+ else
+ free_heap_pages(pg, order, 0);
}
else if ( unlikely(d == dom_cow) )
{
ASSERT(order == 0);
scrub_one_page(pg);
- free_heap_pages(pg, 0);
+ free_heap_pages(pg, 0, 0);
drop_dom_ref = 0;
}
else
{
/* Freeing anonymous domain-heap pages. */
- free_heap_pages(pg, order);
+ free_heap_pages(pg, order, 0);
drop_dom_ref = 0;
}
--
1.7.10.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |