Revert "xen/mm: allow deferred scrub of physmap populate allocated pages"

This reverts commit 6228ea8acd and its
prereq 15cd2b8f1b ("xen/mm: remove
aliasing of PGC_need_scrub over PGC_allocated"). Further fixes are
needed before these can be considered for backporting.
This commit is contained in:
Jan Beulich committed 2026-03-26 11:04:14 +01:00
1 parent 74930b4a9d
commit 73f4c7aab7
9 files changed
+35 -160

No files matched your search

+7 -3
View File
@@ -144,9 +144,6 @@ struct page_info
#define _PGC_colored PG_shift(4)
#define PGC_colored PG_mask(1, 4)
#endif
/* Page needs to be scrubbed. */
#define _PGC_need_scrub PG_shift(5)
#define PGC_need_scrub PG_mask(1, 5)
/* ... */
/* Page is broken? */
#define _PGC_broken PG_shift(7)
@@ -166,6 +163,13 @@ struct page_info
#define PGC_count_width PG_shift(10)
#define PGC_count_mask ((1UL<<PGC_count_width)-1)
/*
* Page needs to be scrubbed. Since this bit can only be set on a page that is
* free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
*/
#define _PGC_need_scrub _PGC_allocated
#define PGC_need_scrub PGC_allocated
#if defined(CONFIG_ARM_64) || defined(CONFIG_MPU)
#define is_xen_heap_page(page) ((page)->count_info & PGC_xen_heap)
#define is_xen_heap_mfn(mfn) \
+7 -3
View File
@@ -57,9 +57,6 @@ static inline struct page_info *virt_to_page(const void *v)
/* Page is Xen heap? */
#define _PGC_xen_heap PG_shift(2)
#define PGC_xen_heap PG_mask(1, 2)
/* Page needs to be scrubbed. */
#define _PGC_need_scrub PG_shift(3)
#define PGC_need_scrub PG_mask(1, 3)
/* Page is broken? */
#define _PGC_broken PG_shift(7)
#define PGC_broken PG_mask(1, 7)
@@ -78,6 +75,13 @@ static inline struct page_info *virt_to_page(const void *v)
#define PGC_count_width PG_shift(10)
#define PGC_count_mask ((1UL<<PGC_count_width)-1)
/*
* Page needs to be scrubbed. Since this bit can only be set on a page that is
* free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
*/
#define _PGC_need_scrub _PGC_allocated
#define PGC_need_scrub PGC_allocated
#define is_xen_heap_page(page) ((page)->count_info & PGC_xen_heap)
#define is_xen_heap_mfn(mfn) \
(mfn_valid(mfn) && is_xen_heap_page(mfn_to_page(mfn)))
+7 -3
View File
@@ -247,15 +247,19 @@ static inline bool arch_mfns_in_directmap(unsigned long mfn, unsigned long nr)
#define PGT_count_width PG_shift(2)
#define PGT_count_mask ((1UL << PGT_count_width) - 1)
/*
* Page needs to be scrubbed. Since this bit can only be set on a page that is
* free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
*/
#define _PGC_need_scrub _PGC_allocated
#define PGC_need_scrub PGC_allocated
/* Cleared when the owning guest 'frees' this page. */
#define _PGC_allocated PG_shift(1)
#define PGC_allocated PG_mask(1, 1)
/* Page is Xen heap? */
#define _PGC_xen_heap PG_shift(2)
#define PGC_xen_heap PG_mask(1, 2)
/* Page needs to be scrubbed. */
#define _PGC_need_scrub PG_shift(4)
#define PGC_need_scrub PG_mask(1, 4)
/* Page is broken? */
#define _PGC_broken PG_shift(7)
#define PGC_broken PG_mask(1, 7)
+11 -7
View File
@@ -83,25 +83,29 @@
#define PGC_state_offlined PG_mask(2, 6)
#define PGC_state_free PG_mask(3, 6)
#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
/* Page needs to be scrubbed. */
#define _PGC_need_scrub PG_shift(7)
#define PGC_need_scrub PG_mask(1, 7)
#ifdef CONFIG_SHADOW_PAGING
/* Set when a page table page has been shadowed. */
#define _PGC_shadowed_pt PG_shift(8)
#define PGC_shadowed_pt PG_mask(1, 8)
#define _PGC_shadowed_pt PG_shift(7)
#define PGC_shadowed_pt PG_mask(1, 7)
#else
#define PGC_shadowed_pt 0
#endif
/* Count of references to this frame. */
#if PGC_shadowed_pt
#define PGC_count_width PG_shift(8)
#else
#define PGC_count_width PG_shift(7)
#else
#define PGC_count_width PG_shift(6)
#endif
#define PGC_count_mask ((1UL<<PGC_count_width)-1)
/*
* Page needs to be scrubbed. Since this bit can only be set on a page that is
* free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
*/
#define _PGC_need_scrub _PGC_allocated
#define PGC_need_scrub PGC_allocated
#ifndef CONFIG_BIGMEM
/*
* This definition is solely for the use in struct page_info (and
-23
View File
@@ -582,18 +582,6 @@ static int __init cf_check parse_dom0_param(const char *s)
}
custom_param("dom0", parse_dom0_param);
static void domain_pending_scrub_free(struct domain *d)
{
rspin_lock(&d->page_alloc_lock);
if ( d->pending_scrub )
{
FREE_DOMHEAP_PAGES(d->pending_scrub, d->pending_scrub_order);
d->pending_scrub_order = 0;
d->pending_scrub_index = 0;
}
rspin_unlock(&d->page_alloc_lock);
}
/*
* Release resources held by a domain. There may or may not be live
* references to the domain, and it may or may not be fully constructed.
@@ -655,7 +643,6 @@ static int domain_teardown(struct domain *d)
/* Trivial teardown, not long-running enough to need a preemption check. */
domain_llc_coloring_free(d);
domain_pending_scrub_free(d);
PROGRESS(gnttab_mappings):
rc = gnttab_release_mappings(d);
@@ -699,7 +686,6 @@ static void _domain_destroy(struct domain *d)
{
BUG_ON(!d->is_dying);
BUG_ON(atomic_read(&d->refcnt) != DOMAIN_DESTROYED);
ASSERT(!d->pending_scrub);
xfree(d->pbuf);
@@ -1665,15 +1651,6 @@ int domain_unpause_by_systemcontroller(struct domain *d)
*/
if ( new == 0 && !d->creation_finished )
{
if ( d->pending_scrub )
{
printk(XENLOG_ERR
"%pd: cannot be started with pending unscrubbed pages, destroying\n",
d);
domain_crash(d);
domain_pending_scrub_free(d);
return -EBUSY;
}
d->creation_finished = true;
arch_domain_creation_finished(d);
}
+1 -104
View File
@@ -159,73 +159,6 @@ static void increase_reservation(struct memop_args *a)
a->nr_done = i;
}
/*
* Temporary storage for a domain assigned page that's not been fully scrubbed.
* Stored pages must be domheap ones.
*
* The stashed page can be freed at any time by Xen, the caller must pass the
* order and NUMA node requirement to the fetch function to ensure the
* currently stashed page matches it's requirements.
*/
static void stash_allocation(struct domain *d, struct page_info *page,
unsigned int order, unsigned int scrub_index)
{
rspin_lock(&d->page_alloc_lock);
/*
* Drop the passed page in preference for the already stashed one. This
* interface is designed to be used for single-threaded domain creation.
*/
if ( d->pending_scrub || d->is_dying )
free_domheap_pages(page, order);
else
{
d->pending_scrub_index = scrub_index;
d->pending_scrub_order = order;
d->pending_scrub = page;
}
rspin_unlock(&d->page_alloc_lock);
}
static struct page_info *get_stashed_allocation(struct domain *d,
unsigned int order,
nodeid_t node,
unsigned int *scrub_index)
{
struct page_info *page = NULL;
rspin_lock(&d->page_alloc_lock);
/*
* If there's a pending page to scrub check if it satisfies the current
* request. If it doesn't free it and return NULL.
*/
if ( d->pending_scrub )
{
if ( d->pending_scrub_order == order &&
(node == NUMA_NO_NODE || node == page_to_nid(d->pending_scrub)) )
{
page = d->pending_scrub;
*scrub_index = d->pending_scrub_index;
}
else
free_domheap_pages(d->pending_scrub, d->pending_scrub_order);
/*
* The caller now owns the page or it has been freed, clear stashed
* information. Prevent concurrent usages of get_stashed_allocation()
* from returning the same page to different contexts.
*/
d->pending_scrub_index = 0;
d->pending_scrub_order = 0;
d->pending_scrub = NULL;
}
rspin_unlock(&d->page_alloc_lock);
return page;
}
static void populate_physmap(struct memop_args *a)
{
struct page_info *page;
@@ -342,19 +275,7 @@ static void populate_physmap(struct memop_args *a)
}
else
{
unsigned int scrub_start = 0;
unsigned int memflags =
a->memflags | (d->creation_finished ? 0
: MEMF_no_scrub);
nodeid_t node =
(a->memflags & MEMF_exact_node) ? MEMF_get_node(a->memflags)
: NUMA_NO_NODE;
page = get_stashed_allocation(d, a->extent_order, node,
&scrub_start);
if ( !page )
page = alloc_domheap_pages(d, a->extent_order, memflags);
page = alloc_domheap_pages(d, a->extent_order, a->memflags);
if ( unlikely(!page) )
{
@@ -365,30 +286,6 @@ static void populate_physmap(struct memop_args *a)
goto out;
}
if ( memflags & MEMF_no_scrub )
{
unsigned int dirty_cnt = 0;
/* Check if there's anything to scrub. */
for ( j = scrub_start; j < (1U << a->extent_order); j++ )
{
if ( !test_and_clear_bit(_PGC_need_scrub,
&page[j].count_info) )
continue;
scrub_one_page(&page[j], true);
if ( (j + 1) != (1U << a->extent_order) &&
!(++dirty_cnt & 0xff) &&
hypercall_preempt_check() )
{
a->preempted = 1;
stash_allocation(d, page, a->extent_order, j + 1);
goto out;
}
}
}
if ( unlikely(a->memflags & MEMF_no_tlbflush) )
{
for ( j = 0; j < (1U << a->extent_order); j++ )
+2 -2
View File
@@ -170,7 +170,7 @@
/*
* Flags that are preserved in assign_pages() (and only there)
*/
#define PGC_preserved (PGC_extra | PGC_static | PGC_colored | PGC_need_scrub)
#define PGC_preserved (PGC_extra | PGC_static | PGC_colored)
#ifndef PGT_TYPE_INFO_INITIALIZER
#define PGT_TYPE_INFO_INITIALIZER 0
@@ -792,7 +792,7 @@ static void page_list_add_scrub(struct page_info *pg, unsigned int node,
# define scrub_page_cold clear_page_cold
#endif
void scrub_one_page(const struct page_info *pg, bool cold)
static void scrub_one_page(const struct page_info *pg, bool cold)
{
void *ptr;
-10
View File
@@ -145,16 +145,6 @@ unsigned long avail_node_heap_pages(unsigned int nodeid);
#define alloc_domheap_page(d,f) (alloc_domheap_pages(d,0,f))
#define free_domheap_page(p) (free_domheap_pages(p,0))
/* Free an allocation, and zero the pointer to it. */
#define FREE_DOMHEAP_PAGES(p, o) do { \
void *_ptr_ = (p); \
(p) = NULL; \
free_domheap_pages(_ptr_, o); \
} while ( false )
#define FREE_DOMHEAP_PAGE(p) FREE_DOMHEAP_PAGES(p, 0)
void scrub_one_page(const struct page_info *pg, bool cold);
int online_page(mfn_t mfn, uint32_t *status);
int offline_page(mfn_t mfn, int broken, uint32_t *status);
int query_page_offline(mfn_t mfn, uint32_t *status);
-5
View File
@@ -662,11 +662,6 @@ struct domain
/* Permission to take ownership of the physical console input. */
bool input_allowed;
} console;
/* Pointer to allocated domheap page that possibly needs scrubbing. */
struct page_info *pending_scrub;
unsigned int pending_scrub_order;
unsigned int pending_scrub_index;
} __aligned(PAGE_SIZE);
static inline struct page_list_head *page_to_list(
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.