memory: add check_get_page_from_gfn() as a wrapper...

...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@citrix.com>
Reviewed-by: Roger Pau Monne <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Julien Grall <julien.grall@arm.com>
This commit is contained in:
Paul Durrant authored and Jan Beulich committed 2018-10-05 16:22:37 +02:00
1 parent 98164cf5a8
commit 02ede7dc03
7 files changed
+78 -59

No files matched your search

+13 -14
View File
@@ -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);
switch ( check_get_page_from_gfn(curr_d, _gfn(gmfn), false, &p2mt,
page) )
{
case 0:
break;
if ( *page == NULL )
case -EAGAIN:
return X86EMUL_RETRY;
default:
ASSERT_UNREACHABLE();
/* Fallthrough */
case -EINVAL:
return X86EMUL_UNHANDLEABLE;
if ( p2m_is_paging(p2mt) )
{
put_page(*page);
p2m_mem_paging_populate(curr_d, gmfn);
return X86EMUL_RETRY;
}
if ( p2m_is_shared(p2mt) )
{
put_page(*page);
return X86EMUL_RETRY;
}
/* This code should not be reached if the gmfn is not RAM */
+1 -13
View File
@@ -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);
if ( check_get_page_from_gfn(d, _gfn(gfn), !writable, &p2mt, &page) )
return NULL;
}
if ( p2m_is_paging(p2mt) )
{
put_page(page);
p2m_mem_paging_populate(d, gfn);
return NULL;
}
if ( writable )
{
+15 -17
View File
@@ -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
+39 -10
View File
@@ -1623,37 +1623,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);
+2 -2
View File
@@ -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))
+2 -3
View File
@@ -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)
{
+6
View File
@@ -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 */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.