[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 3 of 9] Enforce ordering constraints for the page alloc lock in the PoD code



Hi also,
> Hi,
>
> The intent of these first three patches looks good to me, but:
>
> - I think it would be better to generate generic spin-lock-with-level
>   and unlock-with-level wrapper functions rather than generating the
>   various checks and having to assemble them into lock_page_alloc() and
>   unlock_page_alloc() by hand.

The final intent is to have these macros establish ordering constraints
for the fine-grained p2m lock, which is not only "grab a spinlock".
Granted, we do not know yet whether we'll need such a fine-grained
approach, but I think it's worth keeping things separate.

As a side-note, an earlier version of my patches did enforce ordering,
except things got really hairy with mem_sharing_unshare_page (which would
jump levels up to grab shr_lock) and pod sweeps. I (think I) have
solutions for both, but I'm not ready to push those yet.

> - p2m->pod.page_alloc_unlock_level is wrong, I think; I can see that you
>   need somewhere to store the unlock-level but it shouldn't live in
>   the p2m state - it's at most a per-domain variable, so it should
>   live in the struct domain; might as well be beside the lock itself.

Ok, sure. Although I think I need to make clear that this ordering
constraint only applies within the pod code, and that's why I wanted to
keep the book-keeping within the pod struct.

Andres
> Tim.
>
> At 00:33 -0400 on 27 Oct (1319675628), Andres Lagar-Cavilla wrote:
>>  xen/arch/x86/mm/mm-locks.h |  11 +++++++++++
>>  xen/arch/x86/mm/p2m-pod.c  |  40
>> +++++++++++++++++++++++++++-------------
>>  xen/include/asm-x86/p2m.h  |   5 +++++
>>  3 files changed, 43 insertions(+), 13 deletions(-)
>>
>>
>> The page alloc lock is sometimes used in the PoD code, with an
>> explicit expectation of ordering. Use our ordering constructs in the
>> mm layer to enforce this.
>>
>> Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
>>
>> diff -r c915609e4235 -r 332775f72a30 xen/arch/x86/mm/mm-locks.h
>> --- a/xen/arch/x86/mm/mm-locks.h
>> +++ b/xen/arch/x86/mm/mm-locks.h
>> @@ -155,6 +155,17 @@ declare_mm_lock(p2m)
>>  #define p2m_unlock(p)         mm_unlock(&(p)->lock)
>>  #define p2m_locked_by_me(p)   mm_locked_by_me(&(p)->lock)
>>
>> +/* Page alloc lock (per-domain)
>> + *
>> + * This is an external lock, not represented by an mm_lock_t. However,
>> + * pod code uses it in conjunction with the p2m lock, and expecting
>> + * the ordering which we enforce here */
>> +
>> +declare_mm_order_constraint(page_alloc)
>> +#define page_alloc_mm_pre_lock()
>> mm_enforce_order_lock_pre_page_alloc()
>> +#define page_alloc_mm_post_lock(l)
>> mm_enforce_order_lock_post_page_alloc(&(l))
>> +#define page_alloc_mm_unlock(l)    mm_enforce_order_unlock((l))
>> +
>>  /* Paging lock (per-domain)
>>   *
>>   * For shadow pagetables, this lock protects
>> diff -r c915609e4235 -r 332775f72a30 xen/arch/x86/mm/p2m-pod.c
>> --- a/xen/arch/x86/mm/p2m-pod.c
>> +++ b/xen/arch/x86/mm/p2m-pod.c
>> @@ -45,6 +45,20 @@
>>
>>  #define superpage_aligned(_x)  (((_x)&(SUPERPAGE_PAGES-1))==0)
>>
>> +/* Enforce lock ordering when grabbing the "external" page_alloc lock
>> */
>> +static inline void lock_page_alloc(struct p2m_domain *p2m)
>> +{
>> +    page_alloc_mm_pre_lock();
>> +    spin_lock(&(p2m->domain->page_alloc_lock));
>> +    page_alloc_mm_post_lock(p2m->pod.page_alloc_unlock_level);
>> +}
>> +
>> +static inline void unlock_page_alloc(struct p2m_domain *p2m)
>> +{
>> +    page_alloc_mm_unlock(p2m->pod.page_alloc_unlock_level);
>> +    spin_unlock(&(p2m->domain->page_alloc_lock));
>> +}
>> +
>>  /*
>>   * Populate-on-demand functionality
>>   */
>> @@ -100,7 +114,7 @@ p2m_pod_cache_add(struct p2m_domain *p2m
>>          unmap_domain_page(b);
>>      }
>>
>> -    spin_lock(&d->page_alloc_lock);
>> +    lock_page_alloc(p2m);
>>
>>      /* First, take all pages off the domain list */
>>      for(i=0; i < 1 << order ; i++)
>> @@ -128,7 +142,7 @@ p2m_pod_cache_add(struct p2m_domain *p2m
>>       * This may cause "zombie domains" since the page will never be
>> freed. */
>>      BUG_ON( d->arch.relmem != RELMEM_not_started );
>>
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>
>>      return 0;
>>  }
>> @@ -245,7 +259,7 @@ p2m_pod_set_cache_target(struct p2m_doma
>>
>>          /* Grab the lock before checking that pod.super is empty, or
>> the last
>>           * entries may disappear before we grab the lock. */
>> -        spin_lock(&d->page_alloc_lock);
>> +        lock_page_alloc(p2m);
>>
>>          if ( (p2m->pod.count - pod_target) > SUPERPAGE_PAGES
>>               && !page_list_empty(&p2m->pod.super) )
>> @@ -257,7 +271,7 @@ p2m_pod_set_cache_target(struct p2m_doma
>>
>>          ASSERT(page != NULL);
>>
>> -        spin_unlock(&d->page_alloc_lock);
>> +        unlock_page_alloc(p2m);
>>
>>          /* Then free them */
>>          for ( i = 0 ; i < (1 << order) ; i++ )
>> @@ -378,7 +392,7 @@ p2m_pod_empty_cache(struct domain *d)
>>      BUG_ON(!d->is_dying);
>>      spin_barrier(&p2m->lock.lock);
>>
>> -    spin_lock(&d->page_alloc_lock);
>> +    lock_page_alloc(p2m);
>>
>>      while ( (page = page_list_remove_head(&p2m->pod.super)) )
>>      {
>> @@ -403,7 +417,7 @@ p2m_pod_empty_cache(struct domain *d)
>>
>>      BUG_ON(p2m->pod.count != 0);
>>
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>  }
>>
>>  int
>> @@ -417,7 +431,7 @@ p2m_pod_offline_or_broken_hit(struct pag
>>      if ( !(d = page_get_owner(p)) || !(p2m = p2m_get_hostp2m(d)) )
>>          return 0;
>>
>> -    spin_lock(&d->page_alloc_lock);
>> +    lock_page_alloc(p2m);
>>      bmfn = mfn_x(page_to_mfn(p));
>>      page_list_for_each_safe(q, tmp, &p2m->pod.super)
>>      {
>> @@ -448,12 +462,12 @@ p2m_pod_offline_or_broken_hit(struct pag
>>          }
>>      }
>>
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>      return 0;
>>
>>  pod_hit:
>>      page_list_add_tail(p, &d->arch.relmem_list);
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>      return 1;
>>  }
>>
>> @@ -994,7 +1008,7 @@ p2m_pod_demand_populate(struct p2m_domai
>>      if ( q == p2m_guest && gfn > p2m->pod.max_guest )
>>          p2m->pod.max_guest = gfn;
>>
>> -    spin_lock(&d->page_alloc_lock);
>> +    lock_page_alloc(p2m);
>>
>>      if ( p2m->pod.count == 0 )
>>          goto out_of_memory;
>> @@ -1008,7 +1022,7 @@ p2m_pod_demand_populate(struct p2m_domai
>>
>>      BUG_ON((mfn_x(mfn) & ((1 << order)-1)) != 0);
>>
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>
>>      gfn_aligned = (gfn >> order) << order;
>>
>> @@ -1040,7 +1054,7 @@ p2m_pod_demand_populate(struct p2m_domai
>>
>>      return 0;
>>  out_of_memory:
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>
>>      printk("%s: Out of populate-on-demand memory! tot_pages %" PRIu32 "
>> pod_entries %" PRIi32 "\n",
>>             __func__, d->tot_pages, p2m->pod.entry_count);
>> @@ -1049,7 +1063,7 @@ out_fail:
>>      return -1;
>>  remap_and_retry:
>>      BUG_ON(order != PAGE_ORDER_2M);
>> -    spin_unlock(&d->page_alloc_lock);
>> +    unlock_page_alloc(p2m);
>>
>>      /* Remap this 2-meg region in singleton chunks */
>>      gfn_aligned = (gfn>>order)<<order;
>> diff -r c915609e4235 -r 332775f72a30 xen/include/asm-x86/p2m.h
>> --- a/xen/include/asm-x86/p2m.h
>> +++ b/xen/include/asm-x86/p2m.h
>> @@ -270,6 +270,10 @@ struct p2m_domain {
>>       * + p2m_pod_demand_populate() grabs both; the p2m lock to avoid
>>       *   double-demand-populating of pages, the page_alloc lock to
>>       *   protect moving stuff from the PoD cache to the domain page
>> list.
>> +     *
>> +     * We enforce this lock ordering through a construct in mm-locks.h.
>> +     * This demands, however, that we store the previous lock-ordering
>> +     * level in effect before grabbing the page_alloc lock.
>>       */
>>      struct {
>>          struct page_list_head super,   /* List of superpages
>>     */
>> @@ -279,6 +283,7 @@ struct p2m_domain {
>>          unsigned         reclaim_super; /* Last gpfn of a scan */
>>          unsigned         reclaim_single; /* Last gpfn of a scan */
>>          unsigned         max_guest;    /* gpfn of max guest
>> demand-populate */
>> +        int              page_alloc_unlock_level; /* To enforce lock
>> ordering */
>>      } pod;
>>  };
>>
>>
>> _______________________________________________
>> Xen-devel mailing list
>> Xen-devel@xxxxxxxxxxxxxxxxxxx
>> http://lists.xensource.com/xen-devel
>



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.