mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
This patch defines a new PGT type called PGT_shared_page and a new synthetic
domain called 'dom_cow'. In order to share a page, the type needs to be changed to PGT_shared_page and the owner to dom_dow. Only pages with PGT_none, and no type count are allowed to become sharable. Conversly, sharable pages can only be made 'private' if type count equals one. page_make_sharable() and page_make_private() handle these transitions. Signed-off-by: Grzegorz Milos <Grzegorz.Milos@citrix.com>
This commit is contained in:
1 parent
287d07f6a7
commit
38edca187d
4 files changed
+134
-22
No files matched your search
+97
-1
@@ -138,7 +138,7 @@ l1_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
|
||||
int mem_hotplug = 0;
|
||||
|
||||
/* Private domain structs for DOMID_XEN and DOMID_IO. */
|
||||
struct domain *dom_xen, *dom_io;
|
||||
struct domain *dom_xen, *dom_io, *dom_cow;
|
||||
|
||||
/* Frame table size in pages. */
|
||||
unsigned long max_page;
|
||||
@@ -250,6 +250,13 @@ void __init arch_init_memory(void)
|
||||
*/
|
||||
dom_io = domain_create(DOMID_IO, DOMCRF_dummy, 0);
|
||||
BUG_ON(dom_io == NULL);
|
||||
|
||||
/*
|
||||
* Initialise our DOMID_IO domain.
|
||||
* This domain owns sharable pages.
|
||||
*/
|
||||
dom_cow = domain_create(DOMID_COW, DOMCRF_dummy, 0);
|
||||
BUG_ON(dom_cow == NULL);
|
||||
|
||||
/* First 1MB of RAM is historically marked as I/O. */
|
||||
for ( i = 0; i < 0x100; i++ )
|
||||
@@ -3789,6 +3796,95 @@ int steal_page(
|
||||
return -1;
|
||||
}
|
||||
|
||||
int page_make_sharable(struct domain *d,
|
||||
struct page_info *page,
|
||||
int expected_refcnt)
|
||||
{
|
||||
unsigned long x, nx, y;
|
||||
|
||||
/* Acquire ref first, so that the page doesn't dissapear from us */
|
||||
if(!get_page(page, d))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&d->page_alloc_lock);
|
||||
|
||||
/* Change page type and count atomically */
|
||||
y = page->u.inuse.type_info;
|
||||
nx = PGT_shared_page | PGT_validated | 1;
|
||||
do {
|
||||
x = y;
|
||||
/* We can only change the type if count is zero, and
|
||||
type is PGT_none */
|
||||
if((x & (PGT_type_mask | PGT_count_mask)) != PGT_none)
|
||||
{
|
||||
put_page(page);
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
y = cmpxchg(&page->u.inuse.type_info, x, nx);
|
||||
} while(x != y);
|
||||
|
||||
/* Check if the ref count is 2. The first from PGT_allocated, and the second
|
||||
* from get_page at the top of this function */
|
||||
if(page->count_info != (PGC_allocated | (2 + expected_refcnt)))
|
||||
{
|
||||
/* Return type count back to zero */
|
||||
put_page_and_type(page);
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
page_set_owner(page, dom_cow);
|
||||
d->tot_pages--;
|
||||
page_list_del(page, &d->page_list);
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
|
||||
/* NOTE: We are not putting the page back. In effect this function acquires
|
||||
* one ref and type ref for the caller */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int page_make_private(struct domain *d, struct page_info *page)
|
||||
{
|
||||
unsigned long x, y;
|
||||
|
||||
if(!get_page(page, dom_cow))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&d->page_alloc_lock);
|
||||
|
||||
/* Change page type and count atomically */
|
||||
y = page->u.inuse.type_info;
|
||||
do {
|
||||
x = y;
|
||||
/* We can only change the type if count is one */
|
||||
if((x & (PGT_type_mask | PGT_count_mask)) !=
|
||||
(PGT_shared_page | 1))
|
||||
{
|
||||
put_page(page);
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
y = cmpxchg(&page->u.inuse.type_info, x, PGT_none);
|
||||
} while(x != y);
|
||||
|
||||
/* We dropped type ref above, drop one ref count too */
|
||||
put_page(page);
|
||||
|
||||
/* Change the owner */
|
||||
ASSERT(page_get_owner(page) == dom_cow);
|
||||
page_set_owner(page, d);
|
||||
|
||||
d->tot_pages++;
|
||||
page_list_add_tail(page, &d->page_list);
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
|
||||
put_page(page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __do_update_va_mapping(
|
||||
unsigned long va, u64 val64, unsigned long flags, struct domain *pg_owner)
|
||||
{
|
||||
|
||||
@@ -1145,7 +1145,7 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
|
||||
|
||||
spin_unlock_recursive(&d->page_alloc_lock);
|
||||
}
|
||||
else if ( likely(d != NULL) )
|
||||
else if ( likely(d != NULL) && likely(d != dom_cow) )
|
||||
{
|
||||
/* NB. May recursively lock from relinquish_memory(). */
|
||||
spin_lock_recursive(&d->page_alloc_lock);
|
||||
@@ -1172,6 +1172,13 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
|
||||
|
||||
free_heap_pages(pg, order);
|
||||
}
|
||||
else if ( unlikely(d == dom_cow) )
|
||||
{
|
||||
ASSERT(order == 0);
|
||||
scrub_one_page(pg);
|
||||
free_heap_pages(pg, 0);
|
||||
drop_dom_ref = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Freeing anonymous domain-heap pages. */
|
||||
|
||||
+25
-20
@@ -155,33 +155,34 @@ struct page_info
|
||||
#define PG_mask(x, idx) (x ## UL << PG_shift(idx))
|
||||
|
||||
/* The following page types are MUTUALLY EXCLUSIVE. */
|
||||
#define PGT_none PG_mask(0, 3) /* no special uses of this page */
|
||||
#define PGT_l1_page_table PG_mask(1, 3) /* using as an L1 page table? */
|
||||
#define PGT_l2_page_table PG_mask(2, 3) /* using as an L2 page table? */
|
||||
#define PGT_l3_page_table PG_mask(3, 3) /* using as an L3 page table? */
|
||||
#define PGT_l4_page_table PG_mask(4, 3) /* using as an L4 page table? */
|
||||
#define PGT_seg_desc_page PG_mask(5, 3) /* using this page in a GDT/LDT? */
|
||||
#define PGT_writable_page PG_mask(7, 3) /* has writable mappings? */
|
||||
#define PGT_type_mask PG_mask(7, 3) /* Bits 29-31. */
|
||||
#define PGT_none PG_mask(0, 4) /* no special uses of this page */
|
||||
#define PGT_l1_page_table PG_mask(1, 4) /* using as an L1 page table? */
|
||||
#define PGT_l2_page_table PG_mask(2, 4) /* using as an L2 page table? */
|
||||
#define PGT_l3_page_table PG_mask(3, 4) /* using as an L3 page table? */
|
||||
#define PGT_l4_page_table PG_mask(4, 4) /* using as an L4 page table? */
|
||||
#define PGT_seg_desc_page PG_mask(5, 4) /* using this page in a GDT/LDT? */
|
||||
#define PGT_writable_page PG_mask(7, 4) /* has writable mappings? */
|
||||
#define PGT_shared_page PG_mask(8, 4) /* CoW sharable page */
|
||||
#define PGT_type_mask PG_mask(15, 4) /* Bits 28-31 or 60-63. */
|
||||
|
||||
/* Owning guest has pinned this page to its current type? */
|
||||
#define _PGT_pinned PG_shift(4)
|
||||
#define PGT_pinned PG_mask(1, 4)
|
||||
#define _PGT_pinned PG_shift(5)
|
||||
#define PGT_pinned PG_mask(1, 5)
|
||||
/* Has this page been validated for use as its current type? */
|
||||
#define _PGT_validated PG_shift(5)
|
||||
#define PGT_validated PG_mask(1, 5)
|
||||
#define _PGT_validated PG_shift(6)
|
||||
#define PGT_validated PG_mask(1, 6)
|
||||
/* PAE only: is this an L2 page directory containing Xen-private mappings? */
|
||||
#define _PGT_pae_xen_l2 PG_shift(6)
|
||||
#define PGT_pae_xen_l2 PG_mask(1, 6)
|
||||
#define _PGT_pae_xen_l2 PG_shift(7)
|
||||
#define PGT_pae_xen_l2 PG_mask(1, 7)
|
||||
/* Has this page been *partially* validated for use as its current type? */
|
||||
#define _PGT_partial PG_shift(7)
|
||||
#define PGT_partial PG_mask(1, 7)
|
||||
#define _PGT_partial PG_shift(8)
|
||||
#define PGT_partial PG_mask(1, 8)
|
||||
/* Page is locked? */
|
||||
#define _PGT_locked PG_shift(8)
|
||||
#define PGT_locked PG_mask(1, 8)
|
||||
#define _PGT_locked PG_shift(9)
|
||||
#define PGT_locked PG_mask(1, 9)
|
||||
|
||||
/* Count of uses of this frame as its current type. */
|
||||
#define PGT_count_width PG_shift(8)
|
||||
#define PGT_count_width PG_shift(9)
|
||||
#define PGT_count_mask ((1UL<<PGT_count_width)-1)
|
||||
|
||||
/* Cleared when the owning guest 'frees' this page. */
|
||||
@@ -529,6 +530,10 @@ int steal_page(
|
||||
struct domain *d, struct page_info *page, unsigned int memflags);
|
||||
int donate_page(
|
||||
struct domain *d, struct page_info *page, unsigned int memflags);
|
||||
int page_make_sharable(struct domain *d,
|
||||
struct page_info *page,
|
||||
int expected_refcnt);
|
||||
int page_make_private(struct domain *d, struct page_info *page);
|
||||
|
||||
int map_ldt_shadow_page(unsigned int);
|
||||
|
||||
@@ -551,6 +556,6 @@ unsigned int domain_clamp_alloc_bitsize(struct domain *d, unsigned int bits);
|
||||
|
||||
unsigned long domain_get_maximum_gpfn(struct domain *d);
|
||||
|
||||
extern struct domain *dom_xen, *dom_io; /* for vmcoreinfo */
|
||||
extern struct domain *dom_xen, *dom_io, *dom_cow; /* for vmcoreinfo */
|
||||
|
||||
#endif /* __ASM_X86_MM_H__ */
|
||||
@@ -366,6 +366,10 @@ typedef uint16_t domid_t;
|
||||
*/
|
||||
#define DOMID_XEN (0x7FF2U)
|
||||
|
||||
/*
|
||||
* DOMID_COW is used as the owner of sharable pages */
|
||||
#define DOMID_COW (0x7FF3U)
|
||||
|
||||
/* DOMID_INVALID is used to identity invalid domid */
|
||||
#define DOMID_INVALID (0x7FFFU)
|
||||
|
||||
|
||||