Re: [Xen-devel] [PATCHES v8 1/8] mm: Place unscrubbed pages at the end of pagelist
Hi Jan, On 21/08/17 14:49, Jan Beulich wrote: On 17.08.17 at 12:30,wrote: On 16/08/17 19:33, Boris Ostrovsky wrote: .. so that it's easy to find pages that need to be scrubbed (those pages are now marked with _PGC_need_scrub bit). We keep track of the first unscrubbed page in a page buddy using first_dirty field. For now it can have two values, 0 (whole buddy needs scrubbing) or INVALID_DIRTY_IDX (the buddy does not need to be scrubbed). Subsequent patches will allow scrubbing to be interrupted, resulting in first_dirty taking any value. Signed-off-by: Boris Ostrovsky For the ARM bits: Acked-by: Julien Grall I've started committing the series when I noticed patches 4, 5, and 6 are still lacking ARM side acks. Whoops, thank you for the remainder. You can ack my ack on the 4, 5, and 6: Acked-by: Julien Grall Cheers, -- Julien Grall ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCHES v8 1/8] mm: Place unscrubbed pages at the end of pagelist
>>> On 17.08.17 at 12:30,wrote: > On 16/08/17 19:33, Boris Ostrovsky wrote: >> .. so that it's easy to find pages that need to be scrubbed (those pages are >> now marked with _PGC_need_scrub bit). >> >> We keep track of the first unscrubbed page in a page buddy using first_dirty >> field. For now it can have two values, 0 (whole buddy needs scrubbing) or >> INVALID_DIRTY_IDX (the buddy does not need to be scrubbed). Subsequent > patches >> will allow scrubbing to be interrupted, resulting in first_dirty taking any >> value. >> >> Signed-off-by: Boris Ostrovsky > > For the ARM bits: > > Acked-by: Julien Grall I've started committing the series when I noticed patches 4, 5, and 6 are still lacking ARM side acks. Jan ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCHES v8 1/8] mm: Place unscrubbed pages at the end of pagelist
On 08/18/2017 05:11 AM, Jan Beulich wrote: On 16.08.17 at 20:33,wrote: >> .. so that it's easy to find pages that need to be scrubbed (those pages are >> now marked with _PGC_need_scrub bit). >> >> We keep track of the first unscrubbed page in a page buddy using first_dirty >> field. For now it can have two values, 0 (whole buddy needs scrubbing) or >> INVALID_DIRTY_IDX (the buddy does not need to be scrubbed). Subsequent >> patches >> will allow scrubbing to be interrupted, resulting in first_dirty taking any >> value. >> >> Signed-off-by: Boris Ostrovsky > Reviewed-by: Jan Beulich > with one remark: > >> --- a/xen/common/page_alloc.c >> +++ b/xen/common/page_alloc.c >> @@ -261,7 +261,11 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) >> #ifdef CONFIG_X86 >> const unsigned long *badpage = NULL; >> unsigned int i, array_size; >> + >> +BUILD_BUG_ON(8 * sizeof(((struct page_info *)0)->u.free.first_dirty) < >> + MAX_ORDER + 1); >> #endif >> +BUILD_BUG_ON(sizeof(((struct page_info *)0)->u) != sizeof(unsigned >> long)); > As I'm generally opposed to casts whenever one can get away > without, I dislike these as well. In the case here, short of a local > variable of suitable type, I'd suggest using frame_table instead > of the open-coded cast. If you're fine with that, this can easily > be done while committing. Sure. -boris ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCHES v8 1/8] mm: Place unscrubbed pages at the end of pagelist
>>> On 16.08.17 at 20:33,wrote: > .. so that it's easy to find pages that need to be scrubbed (those pages are > now marked with _PGC_need_scrub bit). > > We keep track of the first unscrubbed page in a page buddy using first_dirty > field. For now it can have two values, 0 (whole buddy needs scrubbing) or > INVALID_DIRTY_IDX (the buddy does not need to be scrubbed). Subsequent patches > will allow scrubbing to be interrupted, resulting in first_dirty taking any > value. > > Signed-off-by: Boris Ostrovsky Reviewed-by: Jan Beulich with one remark: > --- a/xen/common/page_alloc.c > +++ b/xen/common/page_alloc.c > @@ -261,7 +261,11 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) > #ifdef CONFIG_X86 > const unsigned long *badpage = NULL; > unsigned int i, array_size; > + > +BUILD_BUG_ON(8 * sizeof(((struct page_info *)0)->u.free.first_dirty) < > + MAX_ORDER + 1); > #endif > +BUILD_BUG_ON(sizeof(((struct page_info *)0)->u) != sizeof(unsigned > long)); As I'm generally opposed to casts whenever one can get away without, I dislike these as well. In the case here, short of a local variable of suitable type, I'd suggest using frame_table instead of the open-coded cast. If you're fine with that, this can easily be done while committing. Jan ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCHES v8 1/8] mm: Place unscrubbed pages at the end of pagelist
Hi Boris, On 16/08/17 19:33, Boris Ostrovsky wrote: .. so that it's easy to find pages that need to be scrubbed (those pages are now marked with _PGC_need_scrub bit). We keep track of the first unscrubbed page in a page buddy using first_dirty field. For now it can have two values, 0 (whole buddy needs scrubbing) or INVALID_DIRTY_IDX (the buddy does not need to be scrubbed). Subsequent patches will allow scrubbing to be interrupted, resulting in first_dirty taking any value. Signed-off-by: Boris OstrovskyFor the ARM bits: Acked-by: Julien Grall Cheers, --- Changes in v8: * Changed x86's definition of page_info.u.free from using bitfields to natural datatypes * Swapped order of bitfields in page_info.u.free for ARM * Added BUILD_BUG_ON to check page_info.u.free.first_dirty size on x86, moved previously defined BUILD_BUG_ON from init_heap_pages() to init_boot_pages() (to avoid introducing extra '#ifdef x86' and to keep both together) xen/common/page_alloc.c | 159 --- xen/include/asm-arm/mm.h | 17 - xen/include/asm-x86/mm.h | 15 + 3 files changed, 167 insertions(+), 24 deletions(-) diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 444ecf3..a39fd81 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -261,7 +261,11 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) #ifdef CONFIG_X86 const unsigned long *badpage = NULL; unsigned int i, array_size; + +BUILD_BUG_ON(8 * sizeof(((struct page_info *)0)->u.free.first_dirty) < + MAX_ORDER + 1); #endif +BUILD_BUG_ON(sizeof(((struct page_info *)0)->u) != sizeof(unsigned long)); ps = round_pgup(ps); pe = round_pgdown(pe); @@ -375,6 +379,8 @@ 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 unsigned long node_need_scrub[MAX_NUMNODES]; + static unsigned long *avail[MAX_NUMNODES]; static long total_avail_pages; @@ -670,13 +676,30 @@ static void check_low_mem_virq(void) } } +/* Pages that need a scrub are added to tail, otherwise to head. */ +static void page_list_add_scrub(struct page_info *pg, unsigned int node, +unsigned int zone, unsigned int order, +unsigned int first_dirty) +{ +PFN_ORDER(pg) = order; +pg->u.free.first_dirty = first_dirty; + +if ( first_dirty != INVALID_DIRTY_IDX ) +{ +ASSERT(first_dirty < (1U << order)); +page_list_add_tail(pg, (node, zone, order)); +} +else +page_list_add(pg, (node, zone, order)); +} + /* Allocate 2^@order contiguous pages. */ static struct page_info *alloc_heap_pages( unsigned int zone_lo, unsigned int zone_hi, unsigned int order, unsigned int memflags, struct domain *d) { -unsigned int i, j, zone = 0, nodemask_retry = 0; +unsigned int i, j, zone = 0, nodemask_retry = 0, first_dirty; nodeid_t first_node, node = MEMF_get_node(memflags), req_node = node; unsigned long request = 1UL << order; struct page_info *pg; @@ -790,12 +813,26 @@ static struct page_info *alloc_heap_pages( return NULL; found: + +first_dirty = pg->u.free.first_dirty; + /* We may have to halve the chunk a number of times. */ while ( j != order ) { -PFN_ORDER(pg) = --j; -page_list_add_tail(pg, (node, zone, j)); -pg += 1 << j; +j--; +page_list_add_scrub(pg, node, zone, j, +(1U << j) > first_dirty ? +first_dirty : INVALID_DIRTY_IDX); +pg += 1U << j; + +if ( first_dirty != INVALID_DIRTY_IDX ) +{ +/* Adjust first_dirty */ +if ( first_dirty >= 1U << j ) +first_dirty -= 1U << j; +else +first_dirty = 0; /* We've moved past original first_dirty */ +} } ASSERT(avail[node][zone] >= request); @@ -842,12 +879,20 @@ static int reserve_offlined_page(struct page_info *head) unsigned int node = phys_to_nid(page_to_maddr(head)); int zone = page_to_zone(head), i, head_order = PFN_ORDER(head), count = 0; struct page_info *cur_head; -int cur_order; +unsigned int cur_order, first_dirty; ASSERT(spin_is_locked(_lock)); cur_head = head; +/* + * We may break the buddy so let's mark the head as clean. Then, when + * merging chunks back into the heap, we will see whether the chunk has + * unscrubbed pages and set its first_dirty properly. + */ +first_dirty = head->u.free.first_dirty; +head->u.free.first_dirty = INVALID_DIRTY_IDX; + page_list_del(head, (node, zone, head_order)); while ( cur_head < (head + (1 << head_order)) ) @@ -858,6 +903,8 @@ static int
[Xen-devel] [PATCHES v8 1/8] mm: Place unscrubbed pages at the end of pagelist
.. so that it's easy to find pages that need to be scrubbed (those pages are now marked with _PGC_need_scrub bit). We keep track of the first unscrubbed page in a page buddy using first_dirty field. For now it can have two values, 0 (whole buddy needs scrubbing) or INVALID_DIRTY_IDX (the buddy does not need to be scrubbed). Subsequent patches will allow scrubbing to be interrupted, resulting in first_dirty taking any value. Signed-off-by: Boris Ostrovsky--- Changes in v8: * Changed x86's definition of page_info.u.free from using bitfields to natural datatypes * Swapped order of bitfields in page_info.u.free for ARM * Added BUILD_BUG_ON to check page_info.u.free.first_dirty size on x86, moved previously defined BUILD_BUG_ON from init_heap_pages() to init_boot_pages() (to avoid introducing extra '#ifdef x86' and to keep both together) xen/common/page_alloc.c | 159 --- xen/include/asm-arm/mm.h | 17 - xen/include/asm-x86/mm.h | 15 + 3 files changed, 167 insertions(+), 24 deletions(-) diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 444ecf3..a39fd81 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -261,7 +261,11 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) #ifdef CONFIG_X86 const unsigned long *badpage = NULL; unsigned int i, array_size; + +BUILD_BUG_ON(8 * sizeof(((struct page_info *)0)->u.free.first_dirty) < + MAX_ORDER + 1); #endif +BUILD_BUG_ON(sizeof(((struct page_info *)0)->u) != sizeof(unsigned long)); ps = round_pgup(ps); pe = round_pgdown(pe); @@ -375,6 +379,8 @@ 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 unsigned long node_need_scrub[MAX_NUMNODES]; + static unsigned long *avail[MAX_NUMNODES]; static long total_avail_pages; @@ -670,13 +676,30 @@ static void check_low_mem_virq(void) } } +/* Pages that need a scrub are added to tail, otherwise to head. */ +static void page_list_add_scrub(struct page_info *pg, unsigned int node, +unsigned int zone, unsigned int order, +unsigned int first_dirty) +{ +PFN_ORDER(pg) = order; +pg->u.free.first_dirty = first_dirty; + +if ( first_dirty != INVALID_DIRTY_IDX ) +{ +ASSERT(first_dirty < (1U << order)); +page_list_add_tail(pg, (node, zone, order)); +} +else +page_list_add(pg, (node, zone, order)); +} + /* Allocate 2^@order contiguous pages. */ static struct page_info *alloc_heap_pages( unsigned int zone_lo, unsigned int zone_hi, unsigned int order, unsigned int memflags, struct domain *d) { -unsigned int i, j, zone = 0, nodemask_retry = 0; +unsigned int i, j, zone = 0, nodemask_retry = 0, first_dirty; nodeid_t first_node, node = MEMF_get_node(memflags), req_node = node; unsigned long request = 1UL << order; struct page_info *pg; @@ -790,12 +813,26 @@ static struct page_info *alloc_heap_pages( return NULL; found: + +first_dirty = pg->u.free.first_dirty; + /* We may have to halve the chunk a number of times. */ while ( j != order ) { -PFN_ORDER(pg) = --j; -page_list_add_tail(pg, (node, zone, j)); -pg += 1 << j; +j--; +page_list_add_scrub(pg, node, zone, j, +(1U << j) > first_dirty ? +first_dirty : INVALID_DIRTY_IDX); +pg += 1U << j; + +if ( first_dirty != INVALID_DIRTY_IDX ) +{ +/* Adjust first_dirty */ +if ( first_dirty >= 1U << j ) +first_dirty -= 1U << j; +else +first_dirty = 0; /* We've moved past original first_dirty */ +} } ASSERT(avail[node][zone] >= request); @@ -842,12 +879,20 @@ static int reserve_offlined_page(struct page_info *head) unsigned int node = phys_to_nid(page_to_maddr(head)); int zone = page_to_zone(head), i, head_order = PFN_ORDER(head), count = 0; struct page_info *cur_head; -int cur_order; +unsigned int cur_order, first_dirty; ASSERT(spin_is_locked(_lock)); cur_head = head; +/* + * We may break the buddy so let's mark the head as clean. Then, when + * merging chunks back into the heap, we will see whether the chunk has + * unscrubbed pages and set its first_dirty properly. + */ +first_dirty = head->u.free.first_dirty; +head->u.free.first_dirty = INVALID_DIRTY_IDX; + page_list_del(head, (node, zone, head_order)); while ( cur_head < (head + (1 << head_order)) ) @@ -858,6 +903,8 @@ static int reserve_offlined_page(struct page_info *head) if ( page_state_is(cur_head, offlined) ) {