mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Revert "xen/mm: allow deferred scrub of physmap populate allocated pages"
This reverts commitb304f94842and its prereq7e10bb1501("xen/mm: remove aliasing of PGC_need_scrub over PGC_allocated"). Further fixes are needed before this can be considered for backporting.
This commit is contained in:
1 parent
4d25f6e10e
commit
a9730e4953
9 files changed
+35
-163
No files matched your search
@@ -150,9 +150,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)
|
||||
@@ -172,6 +169,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
|
||||
|
||||
#ifdef CONFIG_ARM_32
|
||||
#define is_xen_heap_page(page) is_xen_heap_mfn(page_to_mfn(page))
|
||||
#define is_xen_heap_mfn(mfn) ({ \
|
||||
|
||||
@@ -58,9 +58,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)
|
||||
@@ -79,6 +76,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)))
|
||||
|
||||
@@ -221,15 +221,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -446,18 +446,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.
|
||||
@@ -517,9 +505,6 @@ static int domain_teardown(struct domain *d)
|
||||
case PROG_none:
|
||||
BUILD_BUG_ON(PROG_none != 0);
|
||||
|
||||
/* Trivial teardown, not long-running enough to need a preemption check. */
|
||||
domain_pending_scrub_free(d);
|
||||
|
||||
PROGRESS(gnttab_mappings):
|
||||
rc = gnttab_release_mappings(d);
|
||||
if ( rc )
|
||||
@@ -562,7 +547,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);
|
||||
|
||||
@@ -1494,15 +1478,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
@@ -157,73 +157,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;
|
||||
@@ -340,19 +273,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) )
|
||||
{
|
||||
@@ -363,30 +284,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]);
|
||||
|
||||
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++ )
|
||||
|
||||
@@ -169,7 +169,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
|
||||
@@ -764,7 +764,7 @@ static void page_list_add_scrub(struct page_info *pg, unsigned int node,
|
||||
#endif
|
||||
#define SCRUB_BYTE_PATTERN (SCRUB_PATTERN & 0xff)
|
||||
|
||||
void scrub_one_page(const struct page_info *pg)
|
||||
static void scrub_one_page(const struct page_info *pg)
|
||||
{
|
||||
if ( unlikely(pg->count_info & PGC_broken) )
|
||||
return;
|
||||
|
||||
@@ -144,17 +144,6 @@ unsigned long avail_domheap_pages(void);
|
||||
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);
|
||||
|
||||
unsigned 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);
|
||||
|
||||
@@ -646,11 +646,6 @@ struct domain
|
||||
unsigned int num_llc_colors;
|
||||
const unsigned int *llc_colors;
|
||||
#endif
|
||||
|
||||
/* Pointer to allocated domheap page that possibly needs scrubbing. */
|
||||
struct page_info *pending_scrub;
|
||||
unsigned int pending_scrub_order;
|
||||
unsigned int pending_scrub_index;
|
||||
};
|
||||
|
||||
static inline struct page_list_head *page_to_list(
|
||||
|
||||