|
[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...
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |