# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxx>
# Date 1294933573 0
# Node ID 32b7a4f2d39950aea45bde3dbf4b94f3b53f6535
# Parent b01ef59c8c805df751a8f6ae63cdd5c6a4565255
x86/mm: make page-sharing use the proper typecount functions
instead of having its own cmpxchg loops.
This should remove some confusion about the use of PGT_none,
and also makes page-sharing participate properly in the TLB
flushing discipline.
Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxx>
---
xen/arch/x86/mm.c | 79 ++++++++++++++++++++----------------------------------
1 files changed, 30 insertions(+), 49 deletions(-)
diff -r b01ef59c8c80 -r 32b7a4f2d399 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Thu Jan 13 15:46:13 2011 +0000
+++ b/xen/arch/x86/mm.c Thu Jan 13 15:46:13 2011 +0000
@@ -2367,7 +2367,7 @@ static int __get_page_type(struct page_i
/* No special validation needed for writable pages. */
/* Page tables and GDT/LDT need to be scanned for validity. */
- if ( type == PGT_writable_page )
+ if ( type == PGT_writable_page || type == PGT_shared_page )
nx |= PGT_validated;
}
}
@@ -4167,32 +4167,25 @@ 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))
+ spin_lock(&d->page_alloc_lock);
+
+ /* Change page type and count atomically */
+ if ( !get_page_and_type(page, d, PGT_shared_page) )
+ {
+ spin_unlock(&d->page_alloc_lock);
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 */
+ }
+
+ /* Check it wasn't already sharable and undo if it was */
+ if ( (page->u.inuse.type_info & PGT_count_mask) != 1 )
+ {
+ put_page_and_type(page);
+ spin_unlock(&d->page_alloc_lock);
+ return -EEXIST;
+ }
+
+ /* Check if the ref count is 2. The first from PGT_allocated, and
+ * the second from get_page_and_type at the top of this function */
if(page->count_info != (PGC_allocated | (2 + expected_refcnt)))
{
/* Return type count back to zero */
@@ -4205,39 +4198,27 @@ int page_make_sharable(struct domain *d,
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);
+ /* We can only change the type if count is one */
+ if ( (page->u.inuse.type_info & (PGT_type_mask | PGT_count_mask))
+ != (PGT_shared_page | 1) )
+ {
+ put_page(page);
+ spin_unlock(&d->page_alloc_lock);
+ return -EEXIST;
+ }
+
+ /* Drop the final typecount */
+ put_page_and_type(page);
/* Change the owner */
ASSERT(page_get_owner(page) == dom_cow);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|