[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 3/9] mm: Scrub pages in alloc_heap_pages() if needed
When allocating pages in alloc_heap_pages() first look for clean pages. If none is found then retry, take pages marked as unscrubbed and scrub them. Note that we shouldn't find unscrubbed pages in alloc_heap_pages() yet. However, this will become possible when we stop scrubbing from free_heap_pages() and instead do it from idle loop. Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx> --- xen/common/page_alloc.c | 96 ++++++++++++++++++++++++++++++++++------------ 1 files changed, 71 insertions(+), 25 deletions(-) diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 9dcf6ee..055654d 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -700,34 +700,17 @@ static struct page_info *alloc_heap_pages( unsigned int order, unsigned int memflags, struct domain *d) { - unsigned int i, j, zone = 0, nodemask_retry = 0; - nodeid_t first_node, node = MEMF_get_node(memflags), req_node = node; + unsigned int i, j, zone, nodemask_retry; + nodeid_t first_node, node, req_node; unsigned long request = 1UL << order; struct page_info *pg; - nodemask_t nodemask = (d != NULL ) ? d->node_affinity : node_online_map; - bool_t need_tlbflush = 0; + nodemask_t nodemask; + bool need_scrub, need_tlbflush = false, use_unscrubbed = false; uint32_t tlbflush_timestamp = 0; /* Make sure there are enough bits in memflags for nodeID. */ BUILD_BUG_ON((_MEMF_bits - _MEMF_node) < (8 * sizeof(nodeid_t))); - if ( node == NUMA_NO_NODE ) - { - if ( d != NULL ) - { - node = next_node(d->last_alloc_node, nodemask); - if ( node >= MAX_NUMNODES ) - node = first_node(nodemask); - } - if ( node >= MAX_NUMNODES ) - node = cpu_to_node(smp_processor_id()); - } - first_node = node; - - ASSERT(node < MAX_NUMNODES); - ASSERT(zone_lo <= zone_hi); - ASSERT(zone_hi < NR_ZONES); - if ( unlikely(order > MAX_ORDER) ) return NULL; @@ -741,7 +724,10 @@ static struct page_info *alloc_heap_pages( total_avail_pages + tmem_freeable_pages()) && ((memflags & MEMF_no_refcount) || !d || d->outstanding_pages < request) ) - goto not_found; + { + spin_unlock(&heap_lock); + return NULL; + } /* * TMEM: When available memory is scarce due to tmem absorbing it, allow @@ -754,6 +740,28 @@ static struct page_info *alloc_heap_pages( tmem_freeable_pages() ) goto try_tmem; + again: + + nodemask_retry = 0; + nodemask = (d != NULL ) ? d->node_affinity : node_online_map; + node = req_node = MEMF_get_node(memflags); + if ( node == NUMA_NO_NODE ) + { + if ( d != NULL ) + { + node = next_node(d->last_alloc_node, nodemask); + if ( node >= MAX_NUMNODES ) + node = first_node(nodemask); + } + if ( node >= MAX_NUMNODES ) + node = cpu_to_node(smp_processor_id()); + } + first_node = node; + + ASSERT(node < MAX_NUMNODES); + ASSERT(zone_lo <= zone_hi); + ASSERT(zone_hi < NR_ZONES); + /* * Start with requested node, but exhaust all node memory in requested * zone before failing, only calc new node value if we fail to find memory @@ -769,8 +777,16 @@ 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; + { + if ( (order == 0) || use_unscrubbed || + !pg->u.free.dirty_head ) + goto found; + + page_list_add_tail(pg, &heap(node, zone, j)); + } + } } while ( zone-- > zone_lo ); /* careful: unsigned zone may wrap */ if ( (memflags & MEMF_exact_node) && req_node != NUMA_NO_NODE ) @@ -809,16 +825,32 @@ static struct page_info *alloc_heap_pages( } not_found: + /* + * If we couldn't find clean page let's search again and this time + * take unscrubbed pages if available. + */ + if ( !use_unscrubbed ) + { + use_unscrubbed = true; + goto again; + } + /* No suitable memory blocks. Fail the request. */ spin_unlock(&heap_lock); return NULL; found: + need_scrub = pg->u.free.dirty_head; + /* We may have to halve the chunk a number of times. */ while ( j != order ) { - PFN_ORDER(pg) = --j; - page_list_add(pg, &heap(node, zone, j)); + /* + * Some of the sub-chunks may be clean but we will mark them + * as dirty (if need_scrub is set) to avoid traversing the + * array here. + */ + page_list_add_scrub(pg, node, zone, --j, need_scrub); pg += 1 << j; } @@ -832,6 +864,20 @@ static struct page_info *alloc_heap_pages( if ( d != NULL ) d->last_alloc_node = node; + if ( need_scrub ) + { + for ( i = 0; i < (1 << order); i++ ) + { + if ( test_bit(_PGC_need_scrub, &pg[i].count_info) ) + { + scrub_one_page(&pg[i]); + pg[i].count_info &= ~PGC_need_scrub; + node_need_scrub[node]--; + } + } + pg->u.free.dirty_head = false; + } + for ( i = 0; i < (1 << order); i++ ) { /* Reference count must continuously be zero for free pages. */ -- 1.7.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |