ia64/xen-unstable

changeset 19270:4b7d638a8b89

Be careful with page_get_owner() now that owner field can be clobbered
by some users. Introduce get_page_owner_and_reference() where that can
be more useful.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 04 14:28:50 2009 +0000 (2009-03-04)
parents 7f573cb76db4
children 3673926b2375
files xen/arch/x86/mm.c xen/common/grant_table.c xen/common/xencomm.c xen/include/asm-ia64/mm.h xen/include/asm-x86/mm.h
line diff
     1.1 --- a/xen/arch/x86/mm.c	Tue Mar 03 13:22:28 2009 +0000
     1.2 +++ b/xen/arch/x86/mm.c	Wed Mar 04 14:28:50 2009 +0000
     1.3 @@ -371,14 +371,14 @@ void share_xen_page_with_privileged_gues
     1.4  #else
     1.5  /*
     1.6   * In debug builds we shadow a selection of <4GB PDPTs to exercise code paths.
     1.7 - * We cannot safely shadow the idle page table, nor shadow (v1) page tables
     1.8 - * (detected by lack of an owning domain). As required for correctness, we
     1.9 + * We cannot safely shadow the idle page table, nor shadow page tables
    1.10 + * (detected by zero reference count). As required for correctness, we
    1.11   * always shadow PDPTs above 4GB.
    1.12   */
    1.13 -#define l3tab_needs_shadow(mfn)                         \
    1.14 -    (((((mfn) << PAGE_SHIFT) != __pa(idle_pg_table)) && \
    1.15 -      (page_get_owner(mfn_to_page(mfn)) != NULL) &&     \
    1.16 -      ((mfn) & 1)) || /* odd MFNs are shadowed */       \
    1.17 +#define l3tab_needs_shadow(mfn)                          \
    1.18 +    (((((mfn) << PAGE_SHIFT) != __pa(idle_pg_table)) &&  \
    1.19 +      (mfn_to_page(mfn)->count_info & PGC_count_mask) && \
    1.20 +      ((mfn) & 1)) || /* odd MFNs are shadowed */        \
    1.21       ((mfn) >= 0x100000))
    1.22  #endif
    1.23  
    1.24 @@ -690,7 +690,16 @@ get_##level##_linear_pagetable(         
    1.25  
    1.26  int is_iomem_page(unsigned long mfn)
    1.27  {
    1.28 -    return (!mfn_valid(mfn) || (page_get_owner(mfn_to_page(mfn)) == dom_io));
    1.29 +    struct page_info *page;
    1.30 +
    1.31 +    if ( !mfn_valid(mfn) )
    1.32 +        return 1;
    1.33 +
    1.34 +    /* Caller must know that it is an iomem page, or a reference is held. */
    1.35 +    page = mfn_to_page(mfn);
    1.36 +    ASSERT((page->count_info & PGC_count_mask) != 0);
    1.37 +
    1.38 +    return (page_get_owner(page) == dom_io);
    1.39  }
    1.40  
    1.41  
    1.42 @@ -703,7 +712,6 @@ get_page_from_l1e(
    1.43      uint32_t l1f = l1e_get_flags(l1e);
    1.44      struct vcpu *curr = current;
    1.45      struct domain *owner;
    1.46 -    int okay;
    1.47  
    1.48      if ( !(l1f & _PAGE_PRESENT) )
    1.49          return 1;
    1.50 @@ -714,8 +722,13 @@ get_page_from_l1e(
    1.51          return 0;
    1.52      }
    1.53  
    1.54 -    if ( is_iomem_page(mfn) )
    1.55 +    if ( !mfn_valid(mfn) ||
    1.56 +         (owner = page_get_owner_and_reference(page)) == dom_io )
    1.57      {
    1.58 +        /* Only needed the reference to confirm dom_io ownership. */
    1.59 +        if ( mfn_valid(mfn) )
    1.60 +            put_page(page);
    1.61 +
    1.62          /* DOMID_IO reverts to caller for privilege checks. */
    1.63          if ( d == dom_io )
    1.64              d = curr->domain;
    1.65 @@ -731,33 +744,29 @@ get_page_from_l1e(
    1.66          return 1;
    1.67      }
    1.68  
    1.69 +    if ( owner == NULL )
    1.70 +        goto could_not_pin;
    1.71 +
    1.72      /*
    1.73       * Let privileged domains transfer the right to map their target
    1.74       * domain's pages. This is used to allow stub-domain pvfb export to dom0,
    1.75       * until pvfb supports granted mappings. At that time this minor hack
    1.76       * can go away.
    1.77       */
    1.78 -    owner = page_get_owner(page);
    1.79 -    if ( unlikely(d != owner) && (owner != NULL) &&
    1.80 -         (d != curr->domain) && IS_PRIV_FOR(d, owner) )
    1.81 +    if ( unlikely(d != owner) && (d != curr->domain) && IS_PRIV_FOR(d, owner) )
    1.82          d = owner;
    1.83  
    1.84      /* Foreign mappings into guests in shadow external mode don't
    1.85       * contribute to writeable mapping refcounts.  (This allows the
    1.86       * qemu-dm helper process in dom0 to map the domain's memory without
    1.87       * messing up the count of "real" writable mappings.) */
    1.88 -    okay = get_data_page(
    1.89 -        page, d,
    1.90 -        (l1f & _PAGE_RW) && !(paging_mode_external(d) && (d != curr->domain)));
    1.91 -    if ( !okay )
    1.92 -    {
    1.93 -        MEM_LOG("Error getting mfn %lx (pfn %lx) from L1 entry %" PRIpte
    1.94 -                " for dom%d",
    1.95 -                mfn, get_gpfn_from_mfn(mfn),
    1.96 -                l1e_get_intpte(l1e), d->domain_id);
    1.97 -    }
    1.98 -    else if ( pte_flags_to_cacheattr(l1f) !=
    1.99 -              ((page->count_info >> PGC_cacheattr_base) & 7) )
   1.100 +    if ( (l1f & _PAGE_RW) &&
   1.101 +         !(paging_mode_external(d) && (d != curr->domain)) &&
   1.102 +         !get_page_type(page, PGT_writable_page) )
   1.103 +        goto could_not_pin;
   1.104 +
   1.105 +    if ( pte_flags_to_cacheattr(l1f) !=
   1.106 +         ((page->count_info >> PGC_cacheattr_base) & 7) )
   1.107      {
   1.108          unsigned long x, nx, y = page->count_info;
   1.109          unsigned long cacheattr = pte_flags_to_cacheattr(l1f);
   1.110 @@ -786,7 +795,16 @@ get_page_from_l1e(
   1.111  #endif
   1.112      }
   1.113  
   1.114 -    return okay;
   1.115 +    return 1;
   1.116 +
   1.117 + could_not_pin:
   1.118 +    MEM_LOG("Error getting mfn %lx (pfn %lx) from L1 entry %" PRIpte
   1.119 +            " for dom%d",
   1.120 +            mfn, get_gpfn_from_mfn(mfn),
   1.121 +            l1e_get_intpte(l1e), d->domain_id);
   1.122 +    if ( owner != NULL )
   1.123 +        put_page(page);
   1.124 +    return 0;
   1.125  }
   1.126  
   1.127  
   1.128 @@ -1174,7 +1192,7 @@ static int create_pae_xen_mappings(struc
   1.129      for ( i = 0; i < PDPT_L2_ENTRIES; i++ )
   1.130      {
   1.131          l2e = l2e_from_page(
   1.132 -            virt_to_page(page_get_owner(page)->arch.mm_perdomain_pt) + i,
   1.133 +            virt_to_page(d->arch.mm_perdomain_pt) + i,
   1.134              __PAGE_HYPERVISOR);
   1.135          l2e_write(&pl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i], l2e);
   1.136      }
   1.137 @@ -1924,7 +1942,7 @@ void put_page(struct page_info *page)
   1.138  }
   1.139  
   1.140  
   1.141 -int get_page(struct page_info *page, struct domain *domain)
   1.142 +struct domain *page_get_owner_and_reference(struct page_info *page)
   1.143  {
   1.144      unsigned long x, y = page->count_info;
   1.145  
   1.146 @@ -1933,22 +1951,29 @@ int get_page(struct page_info *page, str
   1.147          if ( unlikely((x & PGC_count_mask) == 0) ||  /* Not allocated? */
   1.148               /* Keep one spare reference to be acquired by get_page_light(). */
   1.149               unlikely(((x + 2) & PGC_count_mask) <= 1) ) /* Overflow? */
   1.150 -            goto fail;
   1.151 +            return NULL;
   1.152      }
   1.153      while ( (y = cmpxchg(&page->count_info, x, x + 1)) != x );
   1.154  
   1.155 -    if ( likely(page_get_owner(page) == domain) )
   1.156 +    return page_get_owner(page);
   1.157 +}
   1.158 +
   1.159 +
   1.160 +int get_page(struct page_info *page, struct domain *domain)
   1.161 +{
   1.162 +    struct domain *owner = page_get_owner_and_reference(page);
   1.163 +
   1.164 +    if ( likely(owner == domain) )
   1.165          return 1;
   1.166  
   1.167      put_page(page);
   1.168  
   1.169 - fail:
   1.170      if ( !_shadow_mode_refcounts(domain) && !domain->is_dying )
   1.171          gdprintk(XENLOG_INFO,
   1.172                   "Error pfn %lx: rd=%p, od=%p, caf=%08lx, taf=%"
   1.173                   PRtype_info "\n",
   1.174 -                 page_to_mfn(page), domain, page_get_owner(page),
   1.175 -                 y, page->u.inuse.type_info);
   1.176 +                 page_to_mfn(page), domain, owner,
   1.177 +                 page->count_info, page->u.inuse.type_info);
   1.178      return 0;
   1.179  }
   1.180  
   1.181 @@ -1974,7 +1999,6 @@ static void get_page_light(struct page_i
   1.182      while ( unlikely(y != x) );
   1.183  }
   1.184  
   1.185 -
   1.186  static int alloc_page_type(struct page_info *page, unsigned long type,
   1.187                             int preemptible)
   1.188  {
     2.1 --- a/xen/common/grant_table.c	Tue Mar 03 13:22:28 2009 +0000
     2.2 +++ b/xen/common/grant_table.c	Wed Mar 04 14:28:50 2009 +0000
     2.3 @@ -195,7 +195,7 @@ static void
     2.4  __gnttab_map_grant_ref(
     2.5      struct gnttab_map_grant_ref *op)
     2.6  {
     2.7 -    struct domain *ld, *rd;
     2.8 +    struct domain *ld, *rd, *owner;
     2.9      struct vcpu   *led;
    2.10      int            handle;
    2.11      unsigned long  frame = 0, nr_gets = 0;
    2.12 @@ -336,8 +336,13 @@ static void
    2.13  
    2.14      spin_unlock(&rd->grant_table->lock);
    2.15  
    2.16 -    if ( is_iomem_page(frame) )
    2.17 +    if ( !mfn_valid(frame) ||
    2.18 +         (owner = page_get_owner_and_reference(mfn_to_page(frame))) == dom_io )
    2.19      {
    2.20 +        /* Only needed the reference to confirm dom_io ownership. */
    2.21 +        if ( mfn_valid(frame) )
    2.22 +            put_page(mfn_to_page(frame));
    2.23 +
    2.24          if ( !iomem_access_permitted(rd, frame, frame) )
    2.25          {
    2.26              gdprintk(XENLOG_WARNING,
    2.27 @@ -352,20 +357,11 @@ static void
    2.28          if ( rc != GNTST_okay )
    2.29              goto undo_out;
    2.30      }
    2.31 -    else
    2.32 +    else if ( owner == rd )
    2.33      {
    2.34 -        if ( unlikely(!mfn_valid(frame)) ||
    2.35 -             unlikely(!(gnttab_host_mapping_get_page_type(op, ld, rd) ?
    2.36 -                        get_page_and_type(mfn_to_page(frame), rd,
    2.37 -                                          PGT_writable_page) :
    2.38 -                        get_page(mfn_to_page(frame), rd))) )
    2.39 -        {
    2.40 -            if ( !rd->is_dying )
    2.41 -                gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n",
    2.42 -                         frame);
    2.43 -            rc = GNTST_general_error;
    2.44 -            goto undo_out;
    2.45 -        }
    2.46 +        if ( gnttab_host_mapping_get_page_type(op, ld, rd) &&
    2.47 +             !get_page_type(mfn_to_page(frame), PGT_writable_page) )
    2.48 +            goto could_not_pin;
    2.49  
    2.50          nr_gets++;
    2.51          if ( op->flags & GNTMAP_host_map )
    2.52 @@ -383,6 +379,17 @@ static void
    2.53              }
    2.54          }
    2.55      }
    2.56 +    else
    2.57 +    {
    2.58 +    could_not_pin:
    2.59 +        if ( !rd->is_dying )
    2.60 +            gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n",
    2.61 +                     frame);
    2.62 +        if ( owner != NULL )
    2.63 +            put_page(mfn_to_page(frame));
    2.64 +        rc = GNTST_general_error;
    2.65 +        goto undo_out;
    2.66 +    }
    2.67  
    2.68      if ( need_iommu(ld) &&
    2.69           !(old_pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) &&
     3.1 --- a/xen/common/xencomm.c	Tue Mar 03 13:22:28 2009 +0000
     3.2 +++ b/xen/common/xencomm.c	Wed Mar 04 14:28:50 2009 +0000
     3.3 @@ -51,24 +51,16 @@ xencomm_get_page(unsigned long paddr, st
     3.4          return -EFAULT;
     3.5          
     3.6      *page = maddr_to_page(maddr);
     3.7 -    if ( get_page(*page, current->domain) == 0 )
     3.8 +    if ( !get_page(*page, current->domain) == 0 )
     3.9      {
    3.10 -        if ( page_get_owner(*page) != current->domain )
    3.11 -        {
    3.12 -            /*
    3.13 -             * This page might be a page granted by another domain, or
    3.14 -             * this page is freed with decrease reservation hypercall at
    3.15 -             * the same time.
    3.16 -             */
    3.17 -            gdprintk(XENLOG_WARNING,
    3.18 -                     "bad page is passed. paddr 0x%lx maddr 0x%lx\n",
    3.19 -                     paddr, maddr);
    3.20 -            return -EFAULT;
    3.21 -        }
    3.22 -
    3.23 -        /* Try again. */
    3.24 -        cpu_relax();
    3.25 -        return -EAGAIN;
    3.26 +        /*
    3.27 +         * This page might be a page granted by another domain, or this page 
    3.28 +         * is freed with decrease reservation hypercall at the same time.
    3.29 +         */
    3.30 +        gdprintk(XENLOG_WARNING,
    3.31 +                 "bad page is passed. paddr 0x%lx maddr 0x%lx\n",
    3.32 +                 paddr, maddr);
    3.33 +        return -EFAULT;
    3.34      }
    3.35  
    3.36      return 0;
     4.1 --- a/xen/include/asm-ia64/mm.h	Tue Mar 03 13:22:28 2009 +0000
     4.2 +++ b/xen/include/asm-ia64/mm.h	Wed Mar 04 14:28:50 2009 +0000
     4.3 @@ -200,9 +200,7 @@ static inline void put_page(struct page_
     4.4          free_domheap_page(page);
     4.5  }
     4.6  
     4.7 -/* count_info and ownership are checked atomically. */
     4.8 -static inline int get_page(struct page_info *page,
     4.9 -                           struct domain *domain)
    4.10 +static inline page_get_owner_and_reference(struct page_info *page)
    4.11  {
    4.12      unsigned long x, y = page->count_info;
    4.13  
    4.14 @@ -210,12 +208,21 @@ static inline int get_page(struct page_i
    4.15          x = y;
    4.16          if (unlikely((x & PGC_count_mask) == 0) ||  /* Not allocated? */
    4.17              unlikely(((x + 1) & PGC_count_mask) == 0) ) {/* Count overflow? */
    4.18 -            goto fail;
    4.19 +            return NULL;
    4.20          }
    4.21          y = cmpxchg_acq(&page->count_info, x, x + 1);
    4.22      } while (unlikely(y != x));
    4.23  
    4.24 -    if (likely(page_get_owner(page) == domain))
    4.25 +    return page_get_owner(page);
    4.26 +}
    4.27 +
    4.28 +/* count_info and ownership are checked atomically. */
    4.29 +static inline int get_page(struct page_info *page,
    4.30 +                           struct domain *domain)
    4.31 +{
    4.32 +    struct domain *owner = page_get_owner_and_reference(page);
    4.33 +
    4.34 +    if (likely(owner == domain))
    4.35          return 1;
    4.36  
    4.37      put_page(page);
    4.38 @@ -224,7 +231,7 @@ fail:
    4.39      gdprintk(XENLOG_INFO,
    4.40               "Error pfn %lx: rd=%p, od=%p, caf=%016lx, taf=%" PRtype_info "\n",
    4.41               page_to_mfn(page), domain,
    4.42 -             page_get_owner(page), y, page->u.inuse.type_info);
    4.43 +             owner, page->count_info, page->u.inuse.type_info);
    4.44      return 0;
    4.45  }
    4.46  
     5.1 --- a/xen/include/asm-x86/mm.h	Tue Mar 03 13:22:28 2009 +0000
     5.2 +++ b/xen/include/asm-x86/mm.h	Wed Mar 04 14:28:50 2009 +0000
     5.3 @@ -258,6 +258,7 @@ void cleanup_page_cacheattr(struct page_
     5.4  
     5.5  int is_iomem_page(unsigned long mfn);
     5.6  
     5.7 +struct domain *page_get_owner_and_reference(struct page_info *page);
     5.8  void put_page(struct page_info *page);
     5.9  int  get_page(struct page_info *page, struct domain *domain);
    5.10  void put_page_type(struct page_info *page);