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

Re: [Xen-devel] [PATCH v14 5/9] memory: add check_get_page_from_gfn() as a wrapper...


  • To: Paul Durrant <paul.durrant@xxxxxxxxxx>, <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: George Dunlap <george.dunlap@xxxxxxxxxx>
  • Date: Thu, 4 Oct 2018 17:02:31 +0100
  • Autocrypt: addr=george.dunlap@xxxxxxxxxx; prefer-encrypt=mutual; keydata= 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 q+/kRPrWXpoaQn7FXWGfMqU+NkY9enyrlw==
  • Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>, Wei Liu <wei.liu2@xxxxxxxxxx>, Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>, George Dunlap <George.Dunlap@xxxxxxxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Tim Deegan <tim@xxxxxxx>, Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
  • Delivery-date: Thu, 04 Oct 2018 16:04:16 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Openpgp: preference=signencrypt

On 10/04/2018 11:45 AM, Paul Durrant wrote:
> ...for some uses of get_page_from_gfn().
> 
> There are many occurrences of the following pattern in the code:
> 
>     q = <readonly look-up> ? P2M_ALLOC : P2M_UNSHARE;
>     page = get_page_from_gfn(d, gfn, &p2mt, q);
> 
>     if ( p2m_is_paging(p2mt) )
>     {
>         if ( page )
>             put_page(page);
> 
>         p2m_mem_paging_populate(d, gfn);
>         return <-EAGAIN or equivalent>;
>     }
> 
>     if ( (q & P2M_UNSHARE) && p2m_is_shared(p2mt) )
>     {
>         if ( page )
>             put_page(page);
> 
>         return <-EAGAIN or equivalent>;
>     }
> 
>     if ( !page )
>         return <-EINVAL or equivalent>;
> 
> There are some small differences between the exact way the occurrences
> are coded but the desired semantic is the same.
> 
> This patch introduces a new common implementation of this code in
> check_get_page_from_gfn() and then converts the various open-coded patterns
> into calls to this new function.
> 
> NOTE: A forward declaration of p2m_type_t enum has been introduced in
>       p2m-common.h so that it is possible to declare
>       check_get_page_from_gfn() there rather than having to add
>       duplicate declarations in the per-architecture p2m headers.
> 
> Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
> Reviewed-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
> Acked-by: Julien Grall <julien.grall@xxxxxxx>

Reviewed-by: George Dunlap <george.dunlap@xxxxxxxxxx>

> ---
> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx>
> Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
> Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
> Cc: Tim Deegan <tim@xxxxxxx>
> Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
> 
> v13:
>  - Expanded commit comment.
> 
> v11:
>  - Forward declare p2m_type_t in p2m-common.h to allow the duplicate
>    declarations of check_get_page_from_gfn() to be removed, and hence add
>    Jan's R-b.
> 
> v10:
>  - Expand commit comment to point out the reason for the duplicate
>    declarations of check_get_page_from_gfn().
> 
> v9:
>  - Defer P2M type checks (beyond shared or paging) to the caller.
> 
> v7:
>  - Fix ARM build by introducing p2m_is_readonly() predicate.
>  - Re-name get_paged_frame() -> check_get_page_from_gfn().
>  - Adjust default cases of callers switch-ing on return value.
> 
> v3:
>  - Addressed comments from George.
> 
> v2:
>  - New in v2.
> ---
>  xen/arch/x86/hvm/emulate.c   | 25 +++++++++++-----------
>  xen/arch/x86/hvm/hvm.c       | 14 +------------
>  xen/common/grant_table.c     | 32 ++++++++++++++---------------
>  xen/common/memory.c          | 49 
> +++++++++++++++++++++++++++++++++++---------
>  xen/include/asm-arm/p2m.h    |  4 ++--
>  xen/include/asm-x86/p2m.h    |  5 ++---
>  xen/include/xen/p2m-common.h |  6 ++++++
>  7 files changed, 77 insertions(+), 58 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
> index eab66eab77..cd1d9a7c57 100644
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -356,22 +356,21 @@ static int hvmemul_acquire_page(unsigned long gmfn, 
> struct page_info **page)
>      struct domain *curr_d = current->domain;
>      p2m_type_t p2mt;
>  
> -    *page = get_page_from_gfn(curr_d, gmfn, &p2mt, P2M_UNSHARE);
> -
> -    if ( *page == NULL )
> -        return X86EMUL_UNHANDLEABLE;
> -
> -    if ( p2m_is_paging(p2mt) )
> +    switch ( check_get_page_from_gfn(curr_d, _gfn(gmfn), false, &p2mt,
> +                                     page) )
>      {
> -        put_page(*page);
> -        p2m_mem_paging_populate(curr_d, gmfn);
> -        return X86EMUL_RETRY;
> -    }
> +    case 0:
> +        break;
>  
> -    if ( p2m_is_shared(p2mt) )
> -    {
> -        put_page(*page);
> +    case -EAGAIN:
>          return X86EMUL_RETRY;
> +
> +    default:
> +        ASSERT_UNREACHABLE();
> +        /* Fallthrough */
> +
> +    case -EINVAL:
> +        return X86EMUL_UNHANDLEABLE;
>      }
>  
>      /* This code should not be reached if the gmfn is not RAM */
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index 51fc3ec07f..fa994a36a4 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -2536,20 +2536,8 @@ static void *_hvm_map_guest_frame(unsigned long gfn, 
> bool_t permanent,
>      struct page_info *page;
>      struct domain *d = current->domain;
>  
> -    page = get_page_from_gfn(d, gfn, &p2mt,
> -                             writable ? P2M_UNSHARE : P2M_ALLOC);
> -    if ( (p2m_is_shared(p2mt) && writable) || !page )
> -    {
> -        if ( page )
> -            put_page(page);
> -        return NULL;
> -    }
> -    if ( p2m_is_paging(p2mt) )
> -    {
> -        put_page(page);
> -        p2m_mem_paging_populate(d, gfn);
> +    if ( check_get_page_from_gfn(d, _gfn(gfn), !writable, &p2mt, &page) )
>          return NULL;
> -    }
>  
>      if ( writable )
>      {
> diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
> index 0f0b7b1a49..3604a8812c 100644
> --- a/xen/common/grant_table.c
> +++ b/xen/common/grant_table.c
> @@ -374,25 +374,23 @@ static int get_paged_frame(unsigned long gfn, mfn_t 
> *mfn,
>                             struct page_info **page, bool readonly,
>                             struct domain *rd)
>  {
> -    int rc = GNTST_okay;
>      p2m_type_t p2mt;
> +    int rc;
>  
> -    *mfn = INVALID_MFN;
> -    *page = get_page_from_gfn(rd, gfn, &p2mt,
> -                              readonly ? P2M_ALLOC : P2M_UNSHARE);
> -    if ( !*page )
> +    rc = check_get_page_from_gfn(rd, _gfn(gfn), readonly, &p2mt, page);
> +    switch ( rc )
>      {
> -#ifdef P2M_SHARED_TYPES
> -        if ( p2m_is_shared(p2mt) )
> -            return GNTST_eagain;
> -#endif
> -#ifdef P2M_PAGES_TYPES
> -        if ( p2m_is_paging(p2mt) )
> -        {
> -            p2m_mem_paging_populate(rd, gfn);
> -            return GNTST_eagain;
> -        }
> -#endif
> +    case 0:
> +        break;
> +
> +    case -EAGAIN:
> +        return GNTST_eagain;
> +
> +    default:
> +        ASSERT_UNREACHABLE();
> +        /* Fallthrough */
> +
> +    case -EINVAL:
>          return GNTST_bad_page;
>      }
>  
> @@ -406,7 +404,7 @@ static int get_paged_frame(unsigned long gfn, mfn_t *mfn,
>  
>      *mfn = page_to_mfn(*page);
>  
> -    return rc;
> +    return GNTST_okay;
>  }
>  
>  static inline void
> diff --git a/xen/common/memory.c b/xen/common/memory.c
> index b567bd46bb..52d55dfed7 100644
> --- a/xen/common/memory.c
> +++ b/xen/common/memory.c
> @@ -1626,37 +1626,66 @@ void destroy_ring_for_helper(
>      }
>  }
>  
> -int prepare_ring_for_helper(
> -    struct domain *d, unsigned long gmfn, struct page_info **_page,
> -    void **_va)
> +/*
> + * Acquire a pointer to struct page_info for a specified doman and GFN,
> + * checking whether the page has been paged out, or needs unsharing.
> + * If the function succeeds then zero is returned, page_p is written
> + * with a pointer to the struct page_info with a reference taken, and
> + * p2mt_p it is written with the P2M type of the page. The caller is
> + * responsible for dropping the reference.
> + * If the function fails then an appropriate errno is returned and the
> + * values referenced by page_p and p2mt_p are undefined.
> + */
> +int check_get_page_from_gfn(struct domain *d, gfn_t gfn, bool readonly,
> +                            p2m_type_t *p2mt_p, struct page_info **page_p)
>  {
> -    struct page_info *page;
> +    p2m_query_t q = readonly ? P2M_ALLOC : P2M_UNSHARE;
>      p2m_type_t p2mt;
> -    void *va;
> +    struct page_info *page;
>  
> -    page = get_page_from_gfn(d, gmfn, &p2mt, P2M_UNSHARE);
> +    page = get_page_from_gfn(d, gfn_x(gfn), &p2mt, q);
>  
>  #ifdef CONFIG_HAS_MEM_PAGING
>      if ( p2m_is_paging(p2mt) )
>      {
>          if ( page )
>              put_page(page);
> -        p2m_mem_paging_populate(d, gmfn);
> -        return -ENOENT;
> +
> +        p2m_mem_paging_populate(d, gfn_x(gfn));
> +        return -EAGAIN;
>      }
>  #endif
>  #ifdef CONFIG_HAS_MEM_SHARING
> -    if ( p2m_is_shared(p2mt) )
> +    if ( (q & P2M_UNSHARE) && p2m_is_shared(p2mt) )
>      {
>          if ( page )
>              put_page(page);
> -        return -ENOENT;
> +
> +        return -EAGAIN;
>      }
>  #endif
>  
>      if ( !page )
>          return -EINVAL;
>  
> +    *p2mt_p = p2mt;
> +    *page_p = page;
> +    return 0;
> +}
> +
> +int prepare_ring_for_helper(
> +    struct domain *d, unsigned long gmfn, struct page_info **_page,
> +    void **_va)
> +{
> +    p2m_type_t p2mt;
> +    struct page_info *page;
> +    void *va;
> +    int rc;
> +
> +    rc = check_get_page_from_gfn(d, _gfn(gmfn), false, &p2mt, &page);
> +    if ( rc )
> +        return (rc == -EAGAIN) ? -ENOENT : rc;
> +
>      if ( !get_page_type(page, PGT_writable_page) )
>      {
>          put_page(page);
> diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
> index 8823707c17..c03557544a 100644
> --- a/xen/include/asm-arm/p2m.h
> +++ b/xen/include/asm-arm/p2m.h
> @@ -110,7 +110,7 @@ struct p2m_domain {
>   * future, it's possible to use higher value for pseudo-type and don't store
>   * them in the p2m entry.
>   */
> -typedef enum {
> +enum p2m_type {
>      p2m_invalid = 0,    /* Nothing mapped here */
>      p2m_ram_rw,         /* Normal read/write guest RAM */
>      p2m_ram_ro,         /* Read-only; writes are silently dropped */
> @@ -124,7 +124,7 @@ typedef enum {
>      p2m_iommu_map_rw,   /* Read/write iommu mapping */
>      p2m_iommu_map_ro,   /* Read-only iommu mapping */
>      p2m_max_real_type,  /* Types after this won't be store in the p2m */
> -} p2m_type_t;
> +};
>  
>  /* We use bitmaps and mask to handle groups of types */
>  #define p2m_to_mask(_t) (1UL << (_t))
> diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
> index be3b6fcaf0..d08c595887 100644
> --- a/xen/include/asm-x86/p2m.h
> +++ b/xen/include/asm-x86/p2m.h
> @@ -52,7 +52,7 @@ extern bool_t opt_hap_1gb, opt_hap_2mb;
>   * cannot be non-zero, otherwise, hardware generates io page faults when 
>   * device access those pages. Therefore, p2m_ram_rw has to be defined as 0.
>   */
> -typedef enum {
> +enum p2m_type {
>      p2m_ram_rw = 0,             /* Normal read/write guest RAM */
>      p2m_invalid = 1,            /* Nothing mapped here */
>      p2m_ram_logdirty = 2,       /* Temporarily read-only for log-dirty */
> @@ -72,7 +72,7 @@ typedef enum {
>      p2m_ram_broken = 13,          /* Broken page, access cause domain crash 
> */
>      p2m_map_foreign  = 14,        /* ram pages from foreign domain */
>      p2m_ioreq_server = 15,
> -} p2m_type_t;
> +};
>  
>  /* Modifiers to the query */
>  typedef unsigned int p2m_query_t;
> @@ -503,7 +503,6 @@ static inline struct page_info *get_page_from_gfn(
>      return mfn_valid(_mfn(gfn)) && get_page(page, d) ? page : NULL;
>  }
>  
> -
>  /* General conversion function from mfn to gfn */
>  static inline unsigned long mfn_to_gfn(struct domain *d, mfn_t mfn)
>  {
> diff --git a/xen/include/xen/p2m-common.h b/xen/include/xen/p2m-common.h
> index 74311950ad..f4d30efe5f 100644
> --- a/xen/include/xen/p2m-common.h
> +++ b/xen/include/xen/p2m-common.h
> @@ -32,5 +32,11 @@ unsigned long
>  p2m_pod_decrease_reservation(struct domain *d, gfn_t gfn,
>                               unsigned int order);
>  
> +typedef enum p2m_type p2m_type_t;
> +
> +int __must_check check_get_page_from_gfn(struct domain *d, gfn_t gfn,
> +                                         bool readonly, p2m_type_t *p2mt_p,
> +                                         struct page_info **page_p);
> +
>  
>  #endif /* _XEN_P2M_COMMON_H */
> 


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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