]> xenbits.xensource.com Git - xen.git/commitdiff
x86: Fix get_page() to not drop reference count if it wasn't incremented.
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 17 Mar 2009 15:29:20 +0000 (15:29 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 17 Mar 2009 15:29:20 +0000 (15:29 +0000)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/mm.c

index 006964498f6d684ac4b4cb8e45e67a0799454294..4f58720fed402c785390bec687f98feca5ddc8ec 100644 (file)
@@ -1948,9 +1948,12 @@ struct domain *page_get_owner_and_reference(struct page_info *page)
 
     do {
         x = y;
-        if ( unlikely((x & PGC_count_mask) == 0) ||  /* Not allocated? */
-             /* Keep one spare reference to be acquired by get_page_light(). */
-             unlikely(((x + 2) & PGC_count_mask) <= 1) ) /* Overflow? */
+        /*
+         * Count ==  0: Page is not allocated, so we cannot take a reference.
+         * Count == -1: Reference count would wrap, which is invalid. 
+         * Count == -2: Remaining unused ref is reserved for get_page_light().
+         */
+        if ( unlikely(((x + 2) & PGC_count_mask) <= 2) )
             return NULL;
     }
     while ( (y = cmpxchg(&page->count_info, x, x + 1)) != x );
@@ -1966,7 +1969,8 @@ int get_page(struct page_info *page, struct domain *domain)
     if ( likely(owner == domain) )
         return 1;
 
-    put_page(page);
+    if ( owner != NULL )
+        put_page(page);
 
     if ( !_shadow_mode_refcounts(domain) && !domain->is_dying )
         gdprintk(XENLOG_INFO,