ia64/xen-unstable

changeset 18972:bd33ff263e2c

PoD memory 4/9: Decrease reservation

Handle balloon driver's calls to decrease_reservation properly.
* Replace PoD entries with p2m_none
* Steal memory for the cache instead of freeing, if need be

Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jan 05 10:43:50 2009 +0000 (2009-01-05)
parents f2ba08549466
children 489f35400ef2
files xen/arch/x86/mm/p2m.c xen/common/memory.c xen/include/asm-x86/p2m.h
line diff
     1.1 --- a/xen/arch/x86/mm/p2m.c	Mon Jan 05 10:43:19 2009 +0000
     1.2 +++ b/xen/arch/x86/mm/p2m.c	Mon Jan 05 10:43:50 2009 +0000
     1.3 @@ -253,6 +253,10 @@ p2m_next_level(struct domain *d, mfn_t *
     1.4  /*
     1.5   * Populate-on-demand functionality
     1.6   */
     1.7 +static
     1.8 +int set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, 
     1.9 +                  unsigned int page_order, p2m_type_t p2mt);
    1.10 +
    1.11  int
    1.12  p2m_pod_cache_add(struct domain *d,
    1.13                    struct page_info *page,
    1.14 @@ -364,6 +368,125 @@ p2m_pod_empty_cache(struct domain *d)
    1.15      spin_unlock(&d->page_alloc_lock);
    1.16  }
    1.17  
    1.18 +/* This function is needed for two reasons:
    1.19 + * + To properly handle clearing of PoD entries
    1.20 + * + To "steal back" memory being freed for the PoD cache, rather than
    1.21 + *   releasing it.
    1.22 + *
    1.23 + * Once both of these functions have been completed, we can return and
    1.24 + * allow decrease_reservation() to handle everything else.
    1.25 + */
    1.26 +int
    1.27 +p2m_pod_decrease_reservation(struct domain *d,
    1.28 +                             xen_pfn_t gpfn,
    1.29 +                             unsigned int order)
    1.30 +{
    1.31 +    struct p2m_domain *p2md = d->arch.p2m;
    1.32 +    int ret=0;
    1.33 +    int i;
    1.34 +
    1.35 +    int steal_for_cache = 0;
    1.36 +    int pod = 0, nonpod = 0, ram = 0;
    1.37 +    
    1.38 +
    1.39 +    /* If we don't have any outstanding PoD entries, let things take their
    1.40 +     * course */
    1.41 +    if ( p2md->pod.entry_count == 0 )
    1.42 +        goto out;
    1.43 +
    1.44 +    /* Figure out if we need to steal some freed memory for our cache */
    1.45 +    steal_for_cache =  ( p2md->pod.entry_count > p2md->pod.count );
    1.46 +
    1.47 +    p2m_lock(p2md);
    1.48 +    audit_p2m(d);
    1.49 +
    1.50 +    /* See what's in here. */
    1.51 +    /* FIXME: Add contiguous; query for PSE entries? */
    1.52 +    for ( i=0; i<(1<<order); i++)
    1.53 +    {
    1.54 +        p2m_type_t t;
    1.55 +
    1.56 +        gfn_to_mfn_query(d, gpfn + i, &t);
    1.57 +
    1.58 +        if ( t == p2m_populate_on_demand )
    1.59 +            pod++;
    1.60 +        else
    1.61 +        {
    1.62 +            nonpod++;
    1.63 +            if ( p2m_is_ram(t) )
    1.64 +                ram++;
    1.65 +        }
    1.66 +    }
    1.67 +
    1.68 +    /* No populate-on-demand?  Don't need to steal anything?  Then we're done!*/
    1.69 +    if(!pod && !steal_for_cache)
    1.70 +        goto out_unlock;
    1.71 +
    1.72 +    if ( !nonpod )
    1.73 +    {
    1.74 +        /* All PoD: Mark the whole region invalid and tell caller
    1.75 +         * we're done. */
    1.76 +        set_p2m_entry(d, gpfn, _mfn(INVALID_MFN), order, p2m_invalid);
    1.77 +        p2md->pod.entry_count-=(1<<order); /* Lock: p2m */
    1.78 +        BUG_ON(p2md->pod.entry_count < 0);
    1.79 +        ret = 1;
    1.80 +        goto out_unlock;
    1.81 +    }
    1.82 +
    1.83 +    /* FIXME: Steal contig 2-meg regions for cache */
    1.84 +
    1.85 +    /* Process as long as:
    1.86 +     * + There are PoD entries to handle, or
    1.87 +     * + There is ram left, and we want to steal it
    1.88 +     */
    1.89 +    for ( i=0;
    1.90 +          i<(1<<order) && (pod>0 || (steal_for_cache && ram > 0));
    1.91 +          i++)
    1.92 +    {
    1.93 +        mfn_t mfn;
    1.94 +        p2m_type_t t;
    1.95 +
    1.96 +        mfn = gfn_to_mfn_query(d, gpfn + i, &t);
    1.97 +        if ( t == p2m_populate_on_demand )
    1.98 +        {
    1.99 +            set_p2m_entry(d, gpfn + i, _mfn(INVALID_MFN), 0, p2m_invalid);
   1.100 +            p2md->pod.entry_count--; /* Lock: p2m */
   1.101 +            BUG_ON(p2md->pod.entry_count < 0);
   1.102 +            pod--;
   1.103 +        }
   1.104 +        else if ( steal_for_cache && p2m_is_ram(t) )
   1.105 +        {
   1.106 +            struct page_info *page;
   1.107 +
   1.108 +            ASSERT(mfn_valid(mfn));
   1.109 +
   1.110 +            page = mfn_to_page(mfn);
   1.111 +
   1.112 +            set_p2m_entry(d, gpfn + i, _mfn(INVALID_MFN), 0, p2m_invalid);
   1.113 +            set_gpfn_from_mfn(mfn_x(mfn), INVALID_M2P_ENTRY);
   1.114 +
   1.115 +            p2m_pod_cache_add(d, page, 0);
   1.116 +
   1.117 +            steal_for_cache =  ( p2md->pod.entry_count > p2md->pod.count );
   1.118 +
   1.119 +            nonpod--;
   1.120 +            ram--;
   1.121 +        }
   1.122 +    }    
   1.123 +
   1.124 +    /* If there are no more non-PoD entries, tell decrease_reservation() that
   1.125 +     * there's nothing left to do. */
   1.126 +    if ( nonpod == 0 )
   1.127 +        ret = 1;
   1.128 +
   1.129 +out_unlock:
   1.130 +    audit_p2m(d);
   1.131 +    p2m_unlock(p2md);
   1.132 +
   1.133 +out:
   1.134 +    return ret;
   1.135 +}
   1.136 +
   1.137  void
   1.138  p2m_pod_dump_data(struct domain *d)
   1.139  {
     2.1 --- a/xen/common/memory.c	Mon Jan 05 10:43:19 2009 +0000
     2.2 +++ b/xen/common/memory.c	Mon Jan 05 10:43:50 2009 +0000
     2.3 @@ -192,6 +192,11 @@ static void decrease_reservation(struct 
     2.4          if ( unlikely(__copy_from_guest_offset(&gmfn, a->extent_list, i, 1)) )
     2.5              goto out;
     2.6  
     2.7 +        /* See if populate-on-demand wants to handle this */
     2.8 +        if ( is_hvm_domain(a->domain)
     2.9 +             && p2m_pod_decrease_reservation(a->domain, gmfn, a->extent_order) )
    2.10 +            continue;
    2.11 +
    2.12          for ( j = 0; j < (1 << a->extent_order); j++ )
    2.13              if ( !guest_remove_page(a->domain, gmfn + j) )
    2.14                  goto out;
     3.1 --- a/xen/include/asm-x86/p2m.h	Mon Jan 05 10:43:19 2009 +0000
     3.2 +++ b/xen/include/asm-x86/p2m.h	Mon Jan 05 10:43:50 2009 +0000
     3.3 @@ -258,6 +258,13 @@ void p2m_pod_dump_data(struct domain *d)
     3.4   * (usually in preparation for domain destruction) */
     3.5  void p2m_pod_empty_cache(struct domain *d);
     3.6  
     3.7 +/* Call when decreasing memory reservation to handle PoD entries properly.
     3.8 + * Will return '1' if all entries were handled and nothing more need be done.*/
     3.9 +int
    3.10 +p2m_pod_decrease_reservation(struct domain *d,
    3.11 +                             xen_pfn_t gpfn,
    3.12 +                             unsigned int order);
    3.13 +
    3.14  /* Add a page to a domain's p2m table */
    3.15  int guest_physmap_add_entry(struct domain *d, unsigned long gfn,
    3.16                              unsigned long mfn, unsigned int page_order,