On Thu, 2020-02-20 at 12:59 +0100, Jan Beulich wrote: > On 07.02.2020 19:04, David Woodhouse wrote: > > --- a/xen/arch/x86/mm.c > > +++ b/xen/arch/x86/mm.c > > @@ -488,7 +488,8 @@ void share_xen_page_with_guest(struct page_info *page, struct domain *d, > > > > page_set_owner(page, d); > > smp_wmb(); /* install valid domain ptr before updating refcnt. */ > > - ASSERT((page->count_info & ~PGC_xen_heap) == 0); > > + ASSERT((page->count_info & ~PGC_xen_heap) == PGC_state_inuse || > > + (page->count_info & ~PGC_xen_heap) == PGC_state_uninitialised); > > Can uninitialized pages really make it here? Yep, we share the low 1MiB with dom_io. > > @@ -1389,6 +1391,16 @@ static void free_heap_pages( > > ASSERT(order <= MAX_ORDER); > > ASSERT(node >= 0); > > > > + if ( page_state_is(pg, uninitialised) ) > > + { > > + init_heap_pages(pg, 1 << order, need_scrub); > > + /* > > + * init_heap_pages() will call back into free_heap_pages() for > > + * each page but cannot keep recursing because each page will > > + * be set to PGC_state_inuse first. > > + */ > > + return; > > + } > > spin_lock(&heap_lock); > > Can you also add a blank line above here please? Done. > > @@ -1780,11 +1792,10 @@ int query_page_offline(mfn_t mfn, uint32_t *status) > > * latter is not on a MAX_ORDER boundary, then we reserve the page by > > * not freeing it to the buddy allocator. > > */ > > -static void init_heap_pages( > > - struct page_info *pg, unsigned long nr_pages) > > +static void init_heap_pages(struct page_info *pg, unsigned long nr_pages, > > + bool scrub) > > Is this new parameter strictly needed, i.e. can free_heap_pages() > be called with uninitialized pages which need scrubbing? (The > code change is simple enough, and hence may warrant keeping, but > then the commit message could indicate so in case this isn't a > strict requirement.) Yes, I think it's feasible for the initramfs pages, which is assigned to dom0 from uninitialised pages, to later get freed and then they'll want scrubbing? There *is* a path into free_heap_pages() with the need_scrub argument set, and I'd have to *prove* that it can never happen in order to... I don't know... put a BUG() in that case instead of supporting it? Didn't seem like that was the thing I wanted to do. > > @@ -2301,10 +2316,11 @@ int assign_pages( > > for ( i = 0; i < (1 << order); i++ ) > > { > > ASSERT(page_get_owner(&pg[i]) == NULL); > > - ASSERT(!pg[i].count_info); > > + ASSERT(pg[i].count_info == PGC_state_inuse || > > + pg[i].count_info == PGC_state_uninitialised); > > Same question here: Can uninitialized pages make it here? If > so, wouldn't it be better to correct this, rather than having > the more permissive assertion? Yep, Dom0 initrd on x86. ASSERT((pg[i].count_info & ~PGC_extra) == PGC_state_inuse || (pg[i].count_info & ~PGC_extra) == PGC_state_uninitialised); > > page_set_owner(&pg[i], d); > > smp_wmb(); /* Domain pointer must be visible before updating refcnt. */ > > - pg[i].count_info = PGC_allocated | 1; > > + pg[i].count_info |= PGC_allocated | 1; > > This is too relaxed for my taste: I understand you want to > retain page state, but I suppose other bits would want clearing > nevertheless. You seem to have dropped the ASSERT immediately before the code snippet you cited, in which arbitrary other contents of count_info are not permitted. I put it back, in its current form after I rebase on top of Paul's commit c793d13944b45d assing PGC_extra. > > --- a/xen/include/asm-x86/mm.h > > +++ b/xen/include/asm-x86/mm.h > > @@ -72,12 +72,13 @@ > > * { inuse, offlining, offlined, free, broken_offlining, broken } > > */ > > #define PGC_state PG_mask(7, 9) > > -#define PGC_state_inuse PG_mask(0, 9) > > +#define PGC_state_uninitialised PG_mask(0, 9) > > #define PGC_state_offlining PG_mask(1, 9) > > #define PGC_state_offlined PG_mask(2, 9) > > #define PGC_state_free PG_mask(3, 9) > > #define PGC_state_broken_offlining PG_mask(4, 9) > > #define PGC_state_broken PG_mask(5, 9) > > +#define PGC_state_inuse PG_mask(6, 9) > > Would imo be nice if this most common state was actually > either 1 or 7, for easy recognition. But the most suitable > value to pick may also depend on the outcome of one of the > comments on patch 1. Not quite sure why 1 and 7 are easier to recognise than other values. The important one is that uninitialised has to be zero, since that's the default (because that's what the frame table is memset to. Which is changeable, but non-trivially so).