debuggers.hg

changeset 22791:32b7a4f2d399

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@citrix.com>
author Tim Deegan <Tim.Deegan@citrix.com>
date Thu Jan 13 15:46:13 2011 +0000 (2011-01-13)
parents b01ef59c8c80
children f1a5ac39c15e
files xen/arch/x86/mm.c
line diff
     1.1 --- a/xen/arch/x86/mm.c	Thu Jan 13 15:46:13 2011 +0000
     1.2 +++ b/xen/arch/x86/mm.c	Thu Jan 13 15:46:13 2011 +0000
     1.3 @@ -2367,7 +2367,7 @@ static int __get_page_type(struct page_i
     1.4  
     1.5                  /* No special validation needed for writable pages. */
     1.6                  /* Page tables and GDT/LDT need to be scanned for validity. */
     1.7 -                if ( type == PGT_writable_page )
     1.8 +                if ( type == PGT_writable_page || type == PGT_shared_page )
     1.9                      nx |= PGT_validated;
    1.10              }
    1.11          }
    1.12 @@ -4167,32 +4167,25 @@ int page_make_sharable(struct domain *d,
    1.13                         struct page_info *page, 
    1.14                         int expected_refcnt)
    1.15  {
    1.16 -    unsigned long x, nx, y;
    1.17 -
    1.18 -    /* Acquire ref first, so that the page doesn't dissapear from us */
    1.19 -    if(!get_page(page, d))
    1.20 -        return -EINVAL;
    1.21 -
    1.22      spin_lock(&d->page_alloc_lock);
    1.23  
    1.24      /* Change page type and count atomically */
    1.25 -    y = page->u.inuse.type_info;
    1.26 -    nx = PGT_shared_page | PGT_validated | 1; 
    1.27 -    do {
    1.28 -        x = y;
    1.29 -        /* We can only change the type if count is zero, and 
    1.30 -           type is PGT_none */
    1.31 -        if((x & (PGT_type_mask | PGT_count_mask)) != PGT_none)
    1.32 -        {
    1.33 -            put_page(page);
    1.34 -            spin_unlock(&d->page_alloc_lock);
    1.35 -            return -EEXIST;
    1.36 -        }
    1.37 -        y = cmpxchg(&page->u.inuse.type_info, x, nx);
    1.38 -    } while(x != y);
    1.39 -
    1.40 -    /* Check if the ref count is 2. The first from PGT_allocated, and the second
    1.41 -     * from get_page at the top of this function */
    1.42 +    if ( !get_page_and_type(page, d, PGT_shared_page) )
    1.43 +    {
    1.44 +        spin_unlock(&d->page_alloc_lock);
    1.45 +        return -EINVAL;
    1.46 +    }
    1.47 +
    1.48 +    /* Check it wasn't already sharable and undo if it was */
    1.49 +    if ( (page->u.inuse.type_info & PGT_count_mask) != 1 )
    1.50 +    {
    1.51 +        put_page_and_type(page);
    1.52 +        spin_unlock(&d->page_alloc_lock);
    1.53 +        return -EEXIST;
    1.54 +    }
    1.55 +
    1.56 +    /* Check if the ref count is 2. The first from PGT_allocated, and
    1.57 +     * the second from get_page_and_type at the top of this function */
    1.58      if(page->count_info != (PGC_allocated | (2 + expected_refcnt)))
    1.59      {
    1.60          /* Return type count back to zero */
    1.61 @@ -4205,39 +4198,27 @@ int page_make_sharable(struct domain *d,
    1.62      d->tot_pages--;
    1.63      page_list_del(page, &d->page_list);
    1.64      spin_unlock(&d->page_alloc_lock);
    1.65 -
    1.66 -    /* NOTE: We are not putting the page back. In effect this function acquires
    1.67 -     * one ref and type ref for the caller */
    1.68 -
    1.69      return 0;
    1.70  }
    1.71  
    1.72  int page_make_private(struct domain *d, struct page_info *page)
    1.73  {
    1.74 -    unsigned long x, y;
    1.75 -
    1.76      if(!get_page(page, dom_cow))
    1.77          return -EINVAL;
    1.78      
    1.79      spin_lock(&d->page_alloc_lock);
    1.80  
    1.81 -    /* Change page type and count atomically */
    1.82 -    y = page->u.inuse.type_info;
    1.83 -    do {
    1.84 -        x = y;
    1.85 -        /* We can only change the type if count is one */
    1.86 -        if((x & (PGT_type_mask | PGT_count_mask)) != 
    1.87 -                (PGT_shared_page | 1))
    1.88 -        {
    1.89 -            put_page(page);
    1.90 -            spin_unlock(&d->page_alloc_lock);
    1.91 -            return -EEXIST;
    1.92 -        }
    1.93 -        y = cmpxchg(&page->u.inuse.type_info, x, PGT_none);
    1.94 -    } while(x != y);
    1.95 -
    1.96 -    /* We dropped type ref above, drop one ref count too */
    1.97 -    put_page(page);
    1.98 +    /* We can only change the type if count is one */
    1.99 +    if ( (page->u.inuse.type_info & (PGT_type_mask | PGT_count_mask))
   1.100 +         != (PGT_shared_page | 1) )
   1.101 +    {
   1.102 +        put_page(page);
   1.103 +        spin_unlock(&d->page_alloc_lock);
   1.104 +        return -EEXIST;
   1.105 +    }
   1.106 +
   1.107 +    /* Drop the final typecount */
   1.108 +    put_page_and_type(page);
   1.109  
   1.110      /* Change the owner */
   1.111      ASSERT(page_get_owner(page) == dom_cow);