ia64/xen-unstable

changeset 19104:bcf77bfd1161

x86: Fold page_info lock into type_info.

Fix some racey looking code at the same time.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jan 27 16:02:21 2009 +0000 (2009-01-27)
parents dbf53b739af0
children 31983c30c460
files xen/arch/x86/mm.c xen/arch/x86/mm/shadow/common.c xen/include/asm-x86/mm.h xen/include/asm-x86/paging.h
line diff
     1.1 --- a/xen/arch/x86/mm.c	Tue Jan 27 11:54:22 2009 +0000
     1.2 +++ b/xen/arch/x86/mm.c	Tue Jan 27 16:02:21 2009 +0000
     1.3 @@ -205,11 +205,6 @@ void __init init_frametable(void)
     1.4      }
     1.5  
     1.6      memset(frame_table, 0, nr_pages << PAGE_SHIFT);
     1.7 -
     1.8 -#if defined(__x86_64__)
     1.9 -    for ( i = 0; i < max_page; i ++ )
    1.10 -        spin_lock_init(&frame_table[i].lock);
    1.11 -#endif
    1.12  }
    1.13  
    1.14  void __init arch_init_memory(void)
    1.15 @@ -330,11 +325,7 @@ void share_xen_page_with_guest(
    1.16  
    1.17      page_set_owner(page, d);
    1.18      wmb(); /* install valid domain ptr before updating refcnt. */
    1.19 -#ifdef __i386__
    1.20 -    ASSERT(page->count_info == 0);
    1.21 -#else
    1.22      ASSERT((page->count_info & ~PGC_xen_heap) == 0);
    1.23 -#endif
    1.24  
    1.25      /* Only add to the allocation list if the domain isn't dying. */
    1.26      if ( !d->is_dying )
    1.27 @@ -1543,24 +1534,31 @@ static int free_l4_table(struct page_inf
    1.28  #define free_l4_table(page, preemptible) (-EINVAL)
    1.29  #endif
    1.30  
    1.31 -static void page_lock(struct page_info *page)
    1.32 +static int page_lock(struct page_info *page)
    1.33  {
    1.34 -#if defined(__i386__)
    1.35 -    while ( unlikely(test_and_set_bit(_PGC_locked, &page->count_info)) )
    1.36 -        while ( test_bit(_PGC_locked, &page->count_info) )
    1.37 +    unsigned long x, nx;
    1.38 +
    1.39 +    do {
    1.40 +        while ( (x = page->u.inuse.type_info) & PGT_locked )
    1.41              cpu_relax();
    1.42 -#else
    1.43 -    spin_lock(&page->lock);
    1.44 -#endif
    1.45 +        nx = x + (1 | PGT_locked);
    1.46 +        if ( !(x & PGT_validated) ||
    1.47 +             !(x & PGT_count_mask) ||
    1.48 +             !(nx & PGT_count_mask) )
    1.49 +            return 0;
    1.50 +    } while ( cmpxchg(&page->u.inuse.type_info, x, nx) != x );
    1.51 +
    1.52 +    return 1;
    1.53  }
    1.54  
    1.55  static void page_unlock(struct page_info *page)
    1.56  {
    1.57 -#if defined(__i386__)
    1.58 -    clear_bit(_PGC_locked, &page->count_info);
    1.59 -#else
    1.60 -    spin_unlock(&page->lock);
    1.61 -#endif
    1.62 +    unsigned long x, nx, y = page->u.inuse.type_info;
    1.63 +
    1.64 +    do {
    1.65 +        x = y;
    1.66 +        nx = x - (1 | PGT_locked);
    1.67 +    } while ( (y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x );
    1.68  }
    1.69  
    1.70  /* How to write an entry to the guest pagetables.
    1.71 @@ -1623,19 +1621,15 @@ static int mod_l1_entry(l1_pgentry_t *pl
    1.72      struct vcpu *curr = current;
    1.73      struct domain *d = curr->domain;
    1.74      unsigned long mfn;
    1.75 -    struct page_info *l1pg = mfn_to_page(gl1mfn);
    1.76      p2m_type_t p2mt;
    1.77      int rc = 1;
    1.78  
    1.79 -    page_lock(l1pg);
    1.80 -
    1.81      if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) )
    1.82 -        return page_unlock(l1pg), 0;
    1.83 +        return 0;
    1.84  
    1.85      if ( unlikely(paging_mode_refcounts(d)) )
    1.86      {
    1.87          rc = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr, preserve_ad);
    1.88 -        page_unlock(l1pg);
    1.89          return rc;
    1.90      }
    1.91  
    1.92 @@ -1644,13 +1638,12 @@ static int mod_l1_entry(l1_pgentry_t *pl
    1.93          /* Translate foreign guest addresses. */
    1.94          mfn = mfn_x(gfn_to_mfn(FOREIGNDOM, l1e_get_pfn(nl1e), &p2mt));
    1.95          if ( !p2m_is_ram(p2mt) || unlikely(mfn == INVALID_MFN) )
    1.96 -            return page_unlock(l1pg), 0;
    1.97 +            return 0;
    1.98          ASSERT((mfn & ~(PADDR_MASK >> PAGE_SHIFT)) == 0);
    1.99          nl1e = l1e_from_pfn(mfn, l1e_get_flags(nl1e));
   1.100  
   1.101          if ( unlikely(l1e_get_flags(nl1e) & l1_disallow_mask(d)) )
   1.102          {
   1.103 -            page_unlock(l1pg);
   1.104              MEM_LOG("Bad L1 flags %x",
   1.105                      l1e_get_flags(nl1e) & l1_disallow_mask(d));
   1.106              return 0;
   1.107 @@ -1662,12 +1655,11 @@ static int mod_l1_entry(l1_pgentry_t *pl
   1.108              adjust_guest_l1e(nl1e, d);
   1.109              rc = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,
   1.110                                preserve_ad);
   1.111 -            page_unlock(l1pg);
   1.112              return rc;
   1.113          }
   1.114  
   1.115          if ( unlikely(!get_page_from_l1e(nl1e, FOREIGNDOM)) )
   1.116 -            return page_unlock(l1pg), 0;
   1.117 +            return 0;
   1.118          
   1.119          adjust_guest_l1e(nl1e, d);
   1.120          if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,
   1.121 @@ -1680,11 +1672,9 @@ static int mod_l1_entry(l1_pgentry_t *pl
   1.122      else if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,
   1.123                                       preserve_ad)) )
   1.124      {
   1.125 -        page_unlock(l1pg);
   1.126          return 0;
   1.127      }
   1.128  
   1.129 -    page_unlock(l1pg);
   1.130      put_page_from_l1e(ol1e, d);
   1.131      return rc;
   1.132  }
   1.133 @@ -1694,13 +1684,13 @@ static int mod_l1_entry(l1_pgentry_t *pl
   1.134  static int mod_l2_entry(l2_pgentry_t *pl2e, 
   1.135                          l2_pgentry_t nl2e, 
   1.136                          unsigned long pfn,
   1.137 -                        unsigned long type,
   1.138                          int preserve_ad)
   1.139  {
   1.140      l2_pgentry_t ol2e;
   1.141      struct vcpu *curr = current;
   1.142      struct domain *d = curr->domain;
   1.143      struct page_info *l2pg = mfn_to_page(pfn);
   1.144 +    unsigned long type = l2pg->u.inuse.type_info;
   1.145      int rc = 1;
   1.146  
   1.147      if ( unlikely(!is_guest_l2_slot(d, type, pgentry_ptr_to_slot(pl2e))) )
   1.148 @@ -1709,16 +1699,13 @@ static int mod_l2_entry(l2_pgentry_t *pl
   1.149          return 0;
   1.150      }
   1.151  
   1.152 -    page_lock(l2pg);
   1.153 -
   1.154      if ( unlikely(__copy_from_user(&ol2e, pl2e, sizeof(ol2e)) != 0) )
   1.155 -        return page_unlock(l2pg), 0;
   1.156 +        return 0;
   1.157  
   1.158      if ( l2e_get_flags(nl2e) & _PAGE_PRESENT )
   1.159      {
   1.160          if ( unlikely(l2e_get_flags(nl2e) & L2_DISALLOW_MASK) )
   1.161          {
   1.162 -            page_unlock(l2pg);
   1.163              MEM_LOG("Bad L2 flags %x",
   1.164                      l2e_get_flags(nl2e) & L2_DISALLOW_MASK);
   1.165              return 0;
   1.166 @@ -1729,12 +1716,11 @@ static int mod_l2_entry(l2_pgentry_t *pl
   1.167          {
   1.168              adjust_guest_l2e(nl2e, d);
   1.169              rc = UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr, preserve_ad);
   1.170 -            page_unlock(l2pg);
   1.171              return rc;
   1.172          }
   1.173  
   1.174          if ( unlikely(get_page_from_l2e(nl2e, pfn, d) < 0) )
   1.175 -            return page_unlock(l2pg), 0;
   1.176 +            return 0;
   1.177  
   1.178          adjust_guest_l2e(nl2e, d);
   1.179          if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr,
   1.180 @@ -1747,11 +1733,9 @@ static int mod_l2_entry(l2_pgentry_t *pl
   1.181      else if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr,
   1.182                                       preserve_ad)) )
   1.183      {
   1.184 -        page_unlock(l2pg);
   1.185          return 0;
   1.186      }
   1.187  
   1.188 -    page_unlock(l2pg);
   1.189      put_page_from_l2e(ol2e, pfn);
   1.190      return rc;
   1.191  }
   1.192 @@ -1766,7 +1750,6 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.193      l3_pgentry_t ol3e;
   1.194      struct vcpu *curr = current;
   1.195      struct domain *d = curr->domain;
   1.196 -    struct page_info *l3pg = mfn_to_page(pfn);
   1.197      int rc = 0;
   1.198  
   1.199      if ( unlikely(!is_guest_l3_slot(pgentry_ptr_to_slot(pl3e))) )
   1.200 @@ -1782,16 +1765,13 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.201      if ( is_pv_32bit_domain(d) && (pgentry_ptr_to_slot(pl3e) >= 3) )
   1.202          return -EINVAL;
   1.203  
   1.204 -    page_lock(l3pg);
   1.205 -
   1.206      if ( unlikely(__copy_from_user(&ol3e, pl3e, sizeof(ol3e)) != 0) )
   1.207 -        return page_unlock(l3pg), -EFAULT;
   1.208 +        return -EFAULT;
   1.209  
   1.210      if ( l3e_get_flags(nl3e) & _PAGE_PRESENT )
   1.211      {
   1.212          if ( unlikely(l3e_get_flags(nl3e) & l3_disallow_mask(d)) )
   1.213          {
   1.214 -            page_unlock(l3pg);
   1.215              MEM_LOG("Bad L3 flags %x",
   1.216                      l3e_get_flags(nl3e) & l3_disallow_mask(d));
   1.217              return -EINVAL;
   1.218 @@ -1802,13 +1782,12 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.219          {
   1.220              adjust_guest_l3e(nl3e, d);
   1.221              rc = UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr, preserve_ad);
   1.222 -            page_unlock(l3pg);
   1.223              return rc ? 0 : -EFAULT;
   1.224          }
   1.225  
   1.226          rc = get_page_from_l3e(nl3e, pfn, d, 0, preemptible);
   1.227          if ( unlikely(rc < 0) )
   1.228 -            return page_unlock(l3pg), rc;
   1.229 +            return rc;
   1.230          rc = 0;
   1.231  
   1.232          adjust_guest_l3e(nl3e, d);
   1.233 @@ -1822,7 +1801,6 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.234      else if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr,
   1.235                                       preserve_ad)) )
   1.236      {
   1.237 -        page_unlock(l3pg);
   1.238          return -EFAULT;
   1.239      }
   1.240  
   1.241 @@ -1834,7 +1812,6 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.242          pae_flush_pgd(pfn, pgentry_ptr_to_slot(pl3e), nl3e);
   1.243      }
   1.244  
   1.245 -    page_unlock(l3pg);
   1.246      put_page_from_l3e(ol3e, pfn, 0, 0);
   1.247      return rc;
   1.248  }
   1.249 @@ -1851,7 +1828,6 @@ static int mod_l4_entry(l4_pgentry_t *pl
   1.250      struct vcpu *curr = current;
   1.251      struct domain *d = curr->domain;
   1.252      l4_pgentry_t ol4e;
   1.253 -    struct page_info *l4pg = mfn_to_page(pfn);
   1.254      int rc = 0;
   1.255  
   1.256      if ( unlikely(!is_guest_l4_slot(d, pgentry_ptr_to_slot(pl4e))) )
   1.257 @@ -1860,16 +1836,13 @@ static int mod_l4_entry(l4_pgentry_t *pl
   1.258          return -EINVAL;
   1.259      }
   1.260  
   1.261 -    page_lock(l4pg);
   1.262 -
   1.263      if ( unlikely(__copy_from_user(&ol4e, pl4e, sizeof(ol4e)) != 0) )
   1.264 -        return page_unlock(l4pg), -EFAULT;
   1.265 +        return -EFAULT;
   1.266  
   1.267      if ( l4e_get_flags(nl4e) & _PAGE_PRESENT )
   1.268      {
   1.269          if ( unlikely(l4e_get_flags(nl4e) & L4_DISALLOW_MASK) )
   1.270          {
   1.271 -            page_unlock(l4pg);
   1.272              MEM_LOG("Bad L4 flags %x",
   1.273                      l4e_get_flags(nl4e) & L4_DISALLOW_MASK);
   1.274              return -EINVAL;
   1.275 @@ -1880,13 +1853,12 @@ static int mod_l4_entry(l4_pgentry_t *pl
   1.276          {
   1.277              adjust_guest_l4e(nl4e, d);
   1.278              rc = UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr, preserve_ad);
   1.279 -            page_unlock(l4pg);
   1.280              return rc ? 0 : -EFAULT;
   1.281          }
   1.282  
   1.283          rc = get_page_from_l4e(nl4e, pfn, d, 0, preemptible);
   1.284          if ( unlikely(rc < 0) )
   1.285 -            return page_unlock(l4pg), rc;
   1.286 +            return rc;
   1.287          rc = 0;
   1.288  
   1.289          adjust_guest_l4e(nl4e, d);
   1.290 @@ -1900,11 +1872,9 @@ static int mod_l4_entry(l4_pgentry_t *pl
   1.291      else if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr,
   1.292                                       preserve_ad)) )
   1.293      {
   1.294 -        page_unlock(l4pg);
   1.295          return -EFAULT;
   1.296      }
   1.297  
   1.298 -    page_unlock(l4pg);
   1.299      put_page_from_l4e(ol4e, pfn, 0, 0);
   1.300      return rc;
   1.301  }
   1.302 @@ -2963,7 +2933,6 @@ int do_mmu_update(
   1.303      unsigned int cmd, done = 0;
   1.304      struct vcpu *v = current;
   1.305      struct domain *d = v->domain;
   1.306 -    unsigned long type_info;
   1.307      struct domain_mmap_cache mapcache;
   1.308  
   1.309      if ( unlikely(count & MMU_UPDATE_PREEMPTED) )
   1.310 @@ -3035,24 +3004,9 @@ int do_mmu_update(
   1.311                            (unsigned long)(req.ptr & ~PAGE_MASK));
   1.312              page = mfn_to_page(mfn);
   1.313  
   1.314 -            switch ( (type_info = page->u.inuse.type_info) & PGT_type_mask )
   1.315 -            {
   1.316 -            case PGT_l1_page_table:
   1.317 -            case PGT_l2_page_table:
   1.318 -            case PGT_l3_page_table:
   1.319 -            case PGT_l4_page_table:
   1.320 +            if ( page_lock(page) )
   1.321              {
   1.322 -                if ( paging_mode_refcounts(d) )
   1.323 -                {
   1.324 -                    MEM_LOG("mmu update on auto-refcounted domain!");
   1.325 -                    break;
   1.326 -                }
   1.327 -
   1.328 -                if ( unlikely(!get_page_type(
   1.329 -                    page, type_info & (PGT_type_mask|PGT_pae_xen_l2))) )
   1.330 -                    goto not_a_pt;
   1.331 -
   1.332 -                switch ( type_info & PGT_type_mask )
   1.333 +                switch ( page->u.inuse.type_info & PGT_type_mask )
   1.334                  {
   1.335                  case PGT_l1_page_table:
   1.336                  {
   1.337 @@ -3064,7 +3018,7 @@ int do_mmu_update(
   1.338                  case PGT_l2_page_table:
   1.339                  {
   1.340                      l2_pgentry_t l2e = l2e_from_intpte(req.val);
   1.341 -                    okay = mod_l2_entry(va, l2e, mfn, type_info,
   1.342 +                    okay = mod_l2_entry(va, l2e, mfn,
   1.343                                          cmd == MMU_PT_UPDATE_PRESERVE_AD);
   1.344                  }
   1.345                  break;
   1.346 @@ -3086,31 +3040,23 @@ int do_mmu_update(
   1.347                  }
   1.348                  break;
   1.349  #endif
   1.350 +                case PGT_writable_page:
   1.351 +                    perfc_incr(writable_mmu_updates);
   1.352 +                    okay = paging_write_guest_entry(v, va, req.val, _mfn(mfn));
   1.353 +                    break;
   1.354                  }
   1.355 -
   1.356 -                put_page_type(page);
   1.357 +                page_unlock(page);
   1.358                  if ( rc == -EINTR )
   1.359                      rc = -EAGAIN;
   1.360              }
   1.361 -            break;
   1.362 -
   1.363 -            default:
   1.364 -            not_a_pt:
   1.365 +            else if ( get_page_type(page, PGT_writable_page) )
   1.366              {
   1.367 -                if ( unlikely(!get_page_type(page, PGT_writable_page)) )
   1.368 -                    break;
   1.369 -
   1.370                  perfc_incr(writable_mmu_updates);
   1.371 -
   1.372                  okay = paging_write_guest_entry(v, va, req.val, _mfn(mfn));
   1.373 -
   1.374                  put_page_type(page);
   1.375              }
   1.376 -            break;
   1.377 -            }
   1.378  
   1.379              unmap_domain_page_with_cache(va, &mapcache);
   1.380 -
   1.381              put_page(page);
   1.382              break;
   1.383  
   1.384 @@ -3189,7 +3135,6 @@ static int create_grant_pte_mapping(
   1.385      void *va;
   1.386      unsigned long gmfn, mfn;
   1.387      struct page_info *page;
   1.388 -    unsigned long type;
   1.389      l1_pgentry_t ol1e;
   1.390      struct domain *d = v->domain;
   1.391  
   1.392 @@ -3210,21 +3155,23 @@ static int create_grant_pte_mapping(
   1.393      va = (void *)((unsigned long)va + ((unsigned long)pte_addr & ~PAGE_MASK));
   1.394      page = mfn_to_page(mfn);
   1.395  
   1.396 -    type = page->u.inuse.type_info & PGT_type_mask;
   1.397 -    if ( (type != PGT_l1_page_table) || !get_page_type(page, type) )
   1.398 +    if ( !page_lock(page) )
   1.399      {
   1.400 -        MEM_LOG("Grant map attempted to update a non-L1 page");
   1.401          rc = GNTST_general_error;
   1.402          goto failed;
   1.403      }
   1.404  
   1.405 -    page_lock(page);
   1.406 +    if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.407 +    {
   1.408 +        page_unlock(page);
   1.409 +        rc = GNTST_general_error;
   1.410 +        goto failed;
   1.411 +    }
   1.412  
   1.413      ol1e = *(l1_pgentry_t *)va;
   1.414      if ( !UPDATE_ENTRY(l1, (l1_pgentry_t *)va, ol1e, nl1e, mfn, v, 0) )
   1.415      {
   1.416          page_unlock(page);
   1.417 -        put_page_type(page);
   1.418          rc = GNTST_general_error;
   1.419          goto failed;
   1.420      } 
   1.421 @@ -3234,8 +3181,6 @@ static int create_grant_pte_mapping(
   1.422      if ( !paging_mode_refcounts(d) )
   1.423          put_page_from_l1e(ol1e, d);
   1.424  
   1.425 -    put_page_type(page);
   1.426 - 
   1.427   failed:
   1.428      unmap_domain_page(va);
   1.429      put_page(page);
   1.430 @@ -3250,7 +3195,6 @@ static int destroy_grant_pte_mapping(
   1.431      void *va;
   1.432      unsigned long gmfn, mfn;
   1.433      struct page_info *page;
   1.434 -    unsigned long type;
   1.435      l1_pgentry_t ol1e;
   1.436  
   1.437      gmfn = addr >> PAGE_SHIFT;
   1.438 @@ -3266,15 +3210,18 @@ static int destroy_grant_pte_mapping(
   1.439      va = (void *)((unsigned long)va + ((unsigned long)addr & ~PAGE_MASK));
   1.440      page = mfn_to_page(mfn);
   1.441  
   1.442 -    type = page->u.inuse.type_info & PGT_type_mask;
   1.443 -    if ( (type != PGT_l1_page_table) || !get_page_type(page, type) )
   1.444 +    if ( !page_lock(page) )
   1.445      {
   1.446 -        MEM_LOG("Grant map attempted to update a non-L1 page");
   1.447          rc = GNTST_general_error;
   1.448          goto failed;
   1.449      }
   1.450  
   1.451 -    page_lock(page);
   1.452 +    if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.453 +    {
   1.454 +        page_unlock(page);
   1.455 +        rc = GNTST_general_error;
   1.456 +        goto failed;
   1.457 +    }
   1.458  
   1.459      ol1e = *(l1_pgentry_t *)va;
   1.460      
   1.461 @@ -3284,7 +3231,6 @@ static int destroy_grant_pte_mapping(
   1.462          page_unlock(page);
   1.463          MEM_LOG("PTE entry %lx for address %"PRIx64" doesn't match frame %lx",
   1.464                  (unsigned long)l1e_get_intpte(ol1e), addr, frame);
   1.465 -        put_page_type(page);
   1.466          rc = GNTST_general_error;
   1.467          goto failed;
   1.468      }
   1.469 @@ -3298,13 +3244,11 @@ static int destroy_grant_pte_mapping(
   1.470      {
   1.471          page_unlock(page);
   1.472          MEM_LOG("Cannot delete PTE entry at %p", va);
   1.473 -        put_page_type(page);
   1.474          rc = GNTST_general_error;
   1.475          goto failed;
   1.476      }
   1.477  
   1.478      page_unlock(page);
   1.479 -    put_page_type(page);
   1.480  
   1.481   failed:
   1.482      unmap_domain_page(va);
   1.483 @@ -3332,21 +3276,40 @@ static int create_grant_va_mapping(
   1.484          MEM_LOG("Could not find L1 PTE for address %lx", va);
   1.485          return GNTST_general_error;
   1.486      }
   1.487 +
   1.488 +    if ( !get_page_from_pagenr(gl1mfn, current->domain) )
   1.489 +    {
   1.490 +        guest_unmap_l1e(v, pl1e);
   1.491 +        return GNTST_general_error;
   1.492 +    }
   1.493 +
   1.494      l1pg = mfn_to_page(gl1mfn);
   1.495 -    page_lock(l1pg);
   1.496 +    if ( !page_lock(l1pg) )
   1.497 +    {
   1.498 +        put_page(l1pg);
   1.499 +        guest_unmap_l1e(v, pl1e);
   1.500 +        return GNTST_general_error;
   1.501 +    }
   1.502 +
   1.503 +    if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.504 +    {
   1.505 +        page_unlock(l1pg);
   1.506 +        put_page(l1pg);
   1.507 +        guest_unmap_l1e(v, pl1e);
   1.508 +        return GNTST_general_error;
   1.509 +    }
   1.510 +
   1.511      ol1e = *pl1e;
   1.512      okay = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0);
   1.513 +
   1.514      page_unlock(l1pg);
   1.515 +    put_page(l1pg);
   1.516      guest_unmap_l1e(v, pl1e);
   1.517 -    pl1e = NULL;
   1.518 -
   1.519 -    if ( !okay )
   1.520 -            return GNTST_general_error;
   1.521 -
   1.522 -    if ( !paging_mode_refcounts(d) )
   1.523 +
   1.524 +    if ( okay && !paging_mode_refcounts(d) )
   1.525          put_page_from_l1e(ol1e, d);
   1.526  
   1.527 -    return GNTST_okay;
   1.528 +    return okay ? GNTST_okay : GNTST_general_error;
   1.529  }
   1.530  
   1.531  static int replace_grant_va_mapping(
   1.532 @@ -3364,31 +3327,48 @@ static int replace_grant_va_mapping(
   1.533          return GNTST_general_error;
   1.534      }
   1.535  
   1.536 +    if ( !get_page_from_pagenr(gl1mfn, current->domain) )
   1.537 +    {
   1.538 +        rc = GNTST_general_error;
   1.539 +        goto out;
   1.540 +    }
   1.541 +
   1.542      l1pg = mfn_to_page(gl1mfn);
   1.543 -    page_lock(l1pg);
   1.544 +    if ( !page_lock(l1pg) )
   1.545 +    {
   1.546 +        rc = GNTST_general_error;
   1.547 +        put_page(l1pg);
   1.548 +        goto out;
   1.549 +    }
   1.550 +
   1.551 +    if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.552 +    {
   1.553 +        rc = GNTST_general_error;
   1.554 +        goto unlock_and_out;
   1.555 +    }
   1.556 +
   1.557      ol1e = *pl1e;
   1.558  
   1.559      /* Check that the virtual address supplied is actually mapped to frame. */
   1.560      if ( unlikely(l1e_get_pfn(ol1e) != frame) )
   1.561      {
   1.562 -        page_unlock(l1pg);
   1.563          MEM_LOG("PTE entry %lx for address %lx doesn't match frame %lx",
   1.564                  l1e_get_pfn(ol1e), addr, frame);
   1.565          rc = GNTST_general_error;
   1.566 -        goto out;
   1.567 +        goto unlock_and_out;
   1.568      }
   1.569  
   1.570      /* Delete pagetable entry. */
   1.571      if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0)) )
   1.572      {
   1.573 -        page_unlock(l1pg);
   1.574          MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
   1.575          rc = GNTST_general_error;
   1.576 -        goto out;
   1.577 +        goto unlock_and_out;
   1.578      }
   1.579  
   1.580 + unlock_and_out:
   1.581      page_unlock(l1pg);
   1.582 -
   1.583 +    put_page(l1pg);
   1.584   out:
   1.585      guest_unmap_l1e(v, pl1e);
   1.586      return rc;
   1.587 @@ -3450,20 +3430,42 @@ int replace_grant_host_mapping(
   1.588          return GNTST_general_error;
   1.589      }
   1.590  
   1.591 +    if ( !get_page_from_pagenr(gl1mfn, current->domain) )
   1.592 +    {
   1.593 +        guest_unmap_l1e(curr, pl1e);
   1.594 +        return GNTST_general_error;
   1.595 +    }
   1.596 +
   1.597      l1pg = mfn_to_page(gl1mfn);
   1.598 -    page_lock(l1pg);
   1.599 +    if ( !page_lock(l1pg) )
   1.600 +    {
   1.601 +        put_page(l1pg);
   1.602 +        guest_unmap_l1e(curr, pl1e);
   1.603 +        return GNTST_general_error;
   1.604 +    }
   1.605 +
   1.606 +    if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.607 +    {
   1.608 +        page_unlock(l1pg);
   1.609 +        put_page(l1pg);
   1.610 +        guest_unmap_l1e(curr, pl1e);
   1.611 +        return GNTST_general_error;
   1.612 +    }
   1.613 +
   1.614      ol1e = *pl1e;
   1.615  
   1.616      if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(),
   1.617                                  gl1mfn, curr, 0)) )
   1.618      {
   1.619          page_unlock(l1pg);
   1.620 +        put_page(l1pg);
   1.621          MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
   1.622          guest_unmap_l1e(curr, pl1e);
   1.623          return GNTST_general_error;
   1.624      }
   1.625  
   1.626      page_unlock(l1pg);
   1.627 +    put_page(l1pg);
   1.628      guest_unmap_l1e(curr, pl1e);
   1.629  
   1.630      rc = replace_grant_va_mapping(addr, frame, ol1e, curr);
   1.631 @@ -3525,28 +3527,45 @@ int do_update_va_mapping(unsigned long v
   1.632      l1_pgentry_t   val = l1e_from_intpte(val64);
   1.633      struct vcpu   *v   = current;
   1.634      struct domain *d   = v->domain;
   1.635 +    struct page_info *gl1pg;
   1.636      l1_pgentry_t  *pl1e;
   1.637      unsigned long  vmask, bmap_ptr, gl1mfn;
   1.638      cpumask_t      pmask;
   1.639 -    int            rc  = 0;
   1.640 +    int            rc;
   1.641  
   1.642      perfc_incr(calls_to_update_va);
   1.643  
   1.644 -    if ( unlikely(!access_ok(va, 1) && !paging_mode_external(d)) )
   1.645 -        return -EINVAL;
   1.646 -
   1.647      rc = xsm_update_va_mapping(d, FOREIGNDOM, val);
   1.648      if ( rc )
   1.649          return rc;
   1.650  
   1.651 +    rc = -EINVAL;
   1.652      pl1e = guest_map_l1e(v, va, &gl1mfn);
   1.653 -
   1.654 -    if ( unlikely(!pl1e || !mod_l1_entry(pl1e, val, gl1mfn, 0)) )
   1.655 -        rc = -EINVAL;
   1.656 -
   1.657 +    if ( unlikely(!pl1e || !get_page_from_pagenr(gl1mfn, d)) )
   1.658 +        goto out;
   1.659 +
   1.660 +    gl1pg = mfn_to_page(gl1mfn);
   1.661 +    if ( !page_lock(gl1pg) )
   1.662 +    {
   1.663 +        put_page(gl1pg);
   1.664 +        goto out;
   1.665 +    }
   1.666 +
   1.667 +    if ( (gl1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.668 +    {
   1.669 +        page_unlock(gl1pg);
   1.670 +        put_page(gl1pg);
   1.671 +        goto out;
   1.672 +    }
   1.673 +
   1.674 +    rc = mod_l1_entry(pl1e, val, gl1mfn, 0) ? 0 : -EINVAL;
   1.675 +
   1.676 +    page_unlock(gl1pg);
   1.677 +    put_page(gl1pg);
   1.678 +
   1.679 + out:
   1.680      if ( pl1e )
   1.681          guest_unmap_l1e(v, pl1e);
   1.682 -    pl1e = NULL;
   1.683  
   1.684      process_deferred_ops();
   1.685  
   1.686 @@ -4223,15 +4242,25 @@ int ptwr_do_page_fault(struct vcpu *v, u
   1.687  
   1.688      /* Attempt to read the PTE that maps the VA being accessed. */
   1.689      guest_get_eff_l1e(v, addr, &pte);
   1.690 -    page = l1e_get_page(pte);
   1.691  
   1.692      /* We are looking only for read-only mappings of p.t. pages. */
   1.693      if ( ((l1e_get_flags(pte) & (_PAGE_PRESENT|_PAGE_RW)) != _PAGE_PRESENT) ||
   1.694 -         !mfn_valid(l1e_get_pfn(pte)) ||
   1.695 -         ((page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table) ||
   1.696 -         ((page->u.inuse.type_info & PGT_count_mask) == 0) ||
   1.697 -         (page_get_owner(page) != d) )
   1.698 +         !get_page_from_pagenr(l1e_get_pfn(pte), d) )
   1.699 +        goto bail;
   1.700 +
   1.701 +    page = l1e_get_page(pte);
   1.702 +    if ( !page_lock(page) )
   1.703 +    {
   1.704 +        put_page(page);
   1.705          goto bail;
   1.706 +    }
   1.707 +
   1.708 +    if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table )
   1.709 +    {
   1.710 +        page_unlock(page);
   1.711 +        put_page(page);
   1.712 +        goto bail;
   1.713 +    }
   1.714  
   1.715      ptwr_ctxt.ctxt.regs = regs;
   1.716      ptwr_ctxt.ctxt.force_writeback = 0;
   1.717 @@ -4240,9 +4269,11 @@ int ptwr_do_page_fault(struct vcpu *v, u
   1.718      ptwr_ctxt.cr2 = addr;
   1.719      ptwr_ctxt.pte = pte;
   1.720  
   1.721 -    page_lock(page);
   1.722      rc = x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops);
   1.723 +
   1.724      page_unlock(page);
   1.725 +    put_page(page);
   1.726 +
   1.727      if ( rc == X86EMUL_UNHANDLEABLE )
   1.728          goto bail;
   1.729  
     2.1 --- a/xen/arch/x86/mm/shadow/common.c	Tue Jan 27 11:54:22 2009 +0000
     2.2 +++ b/xen/arch/x86/mm/shadow/common.c	Tue Jan 27 16:02:21 2009 +0000
     2.3 @@ -1722,9 +1722,6 @@ shadow_free_p2m_page(struct domain *d, s
     2.4      /* Free should not decrement domain's total allocation, since 
     2.5       * these pages were allocated without an owner. */
     2.6      page_set_owner(pg, NULL); 
     2.7 -#if defined(__x86_64__)
     2.8 -    spin_lock_init(&pg->lock);
     2.9 -#endif
    2.10      free_domheap_pages(pg, 0);
    2.11      d->arch.paging.shadow.p2m_pages--;
    2.12      perfc_decr(shadow_alloc_count);
    2.13 @@ -1833,14 +1830,6 @@ static unsigned int sh_set_allocation(st
    2.14              sp = list_entry(d->arch.paging.shadow.freelists[order].next,
    2.15                              struct shadow_page_info, list);
    2.16              list_del(&sp->list);
    2.17 -#if defined(__x86_64__)
    2.18 -            /*
    2.19 -             * Re-instate lock field which we overwrite with shadow_page_info.
    2.20 -             * This was safe, since the lock is only used on guest pages.
    2.21 -             */
    2.22 -            for ( j = 0; j < 1U << order; j++ )
    2.23 -                spin_lock_init(&((struct page_info *)sp)[j].lock);
    2.24 -#endif
    2.25              d->arch.paging.shadow.free_pages -= 1 << order;
    2.26              d->arch.paging.shadow.total_pages -= 1 << order;
    2.27              free_domheap_pages((struct page_info *)sp, order);
     3.1 --- a/xen/include/asm-x86/mm.h	Tue Jan 27 11:54:22 2009 +0000
     3.2 +++ b/xen/include/asm-x86/mm.h	Tue Jan 27 16:02:21 2009 +0000
     3.3 @@ -46,10 +46,6 @@ struct page_info
     3.4  
     3.5      } u;
     3.6  
     3.7 -#if defined(__x86_64__)
     3.8 -    spinlock_t lock;
     3.9 -#endif
    3.10 -
    3.11      union {
    3.12          /*
    3.13           * Timestamp from 'TLB clock', used to avoid extra safety flushes.
    3.14 @@ -127,23 +123,20 @@ struct page_info
    3.15  /* Has this page been *partially* validated for use as its current type? */
    3.16  #define _PGT_partial      PG_shift(7)
    3.17  #define PGT_partial       PG_mask(1, 7)
    3.18 + /* Page is locked? */
    3.19 +#define _PGT_locked       PG_shift(8)
    3.20 +#define PGT_locked        PG_mask(1, 8)
    3.21  
    3.22   /* Count of uses of this frame as its current type. */
    3.23 -#define PGT_count_width   PG_shift(7)
    3.24 +#define PGT_count_width   PG_shift(8)
    3.25  #define PGT_count_mask    ((1UL<<PGT_count_width)-1)
    3.26  
    3.27   /* Cleared when the owning guest 'frees' this page. */
    3.28  #define _PGC_allocated    PG_shift(1)
    3.29  #define PGC_allocated     PG_mask(1, 1)
    3.30 -#if defined(__i386__)
    3.31 - /* Page is locked? */
    3.32 -# define _PGC_locked      PG_shift(2)
    3.33 -# define PGC_locked       PG_mask(1, 2)
    3.34 -#else
    3.35   /* Page is Xen heap? */
    3.36 -# define _PGC_xen_heap    PG_shift(2)
    3.37 -# define PGC_xen_heap     PG_mask(1, 2)
    3.38 -#endif
    3.39 +#define _PGC_xen_heap     PG_shift(2)
    3.40 +#define PGC_xen_heap      PG_mask(1, 2)
    3.41   /* Set when is using a page as a page table */
    3.42  #define _PGC_page_table   PG_shift(3)
    3.43  #define PGC_page_table    PG_mask(1, 3)
     4.1 --- a/xen/include/asm-x86/paging.h	Tue Jan 27 11:54:22 2009 +0000
     4.2 +++ b/xen/include/asm-x86/paging.h	Tue Jan 27 16:02:21 2009 +0000
     4.3 @@ -336,7 +336,7 @@ void paging_dump_vcpu_info(struct vcpu *
     4.4   * Access to the guest pagetables */
     4.5  
     4.6  /* Get a mapping of a PV guest's l1e for this virtual address. */
     4.7 -static inline void *
     4.8 +static inline l1_pgentry_t *
     4.9  guest_map_l1e(struct vcpu *v, unsigned long addr, unsigned long *gl1mfn)
    4.10  {
    4.11      l2_pgentry_t l2e;
    4.12 @@ -354,15 +354,14 @@ guest_map_l1e(struct vcpu *v, unsigned l
    4.13           != _PAGE_PRESENT )
    4.14          return NULL;
    4.15      *gl1mfn = l2e_get_pfn(l2e);
    4.16 -    return &__linear_l1_table[l1_linear_offset(addr)];
    4.17 +    return (l1_pgentry_t *)map_domain_page(*gl1mfn) + l1_table_offset(addr);
    4.18  }
    4.19  
    4.20  /* Pull down the mapping we got from guest_map_l1e() */
    4.21  static inline void
    4.22  guest_unmap_l1e(struct vcpu *v, void *p)
    4.23  {
    4.24 -    if ( unlikely(paging_mode_translate(v->domain)) )
    4.25 -        unmap_domain_page(p);
    4.26 +    unmap_domain_page(p);
    4.27  }
    4.28  
    4.29  /* Read the guest's l1e that maps this address. */