[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] New P2M types for memory paging and supporting functions.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1261031275 0 # Node ID 01037b222d745bf1fc07a9720bc1cdb1f70ceed9 # Parent c9fb3c514f65ab5f2c348215fa3affa462e94556 New P2M types for memory paging and supporting functions. Several new types need to be added to represent the various different stages a page can be in while being paged out/in. Xen will sometimes make different decisions based on these types. Signed-off-by: Patrick Colp <Patrick.Colp@xxxxxxxxxx> --- xen/arch/x86/mm/p2m.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/p2m.h | 40 ++++++++++- 2 files changed, 198 insertions(+), 3 deletions(-) diff -r c9fb3c514f65 -r 01037b222d74 xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Thu Dec 17 06:27:55 2009 +0000 +++ b/xen/arch/x86/mm/p2m.c Thu Dec 17 06:27:55 2009 +0000 @@ -3,6 +3,7 @@ * * physical-to-machine mappings for automatically-translated domains. * + * Parts of this code are Copyright (c) 2009 by Citrix (R&D) Ltd. (Patrick Colp) * Parts of this code are Copyright (c) 2007 by Advanced Micro Devices. * Parts of this code are Copyright (c) 2006-2007 by XenSource Inc. * Parts of this code are Copyright (c) 2006 by Michael A Fetterman @@ -29,6 +30,9 @@ #include <asm/p2m.h> #include <asm/hvm/vmx/vmx.h> /* ept_p2m_init() */ #include <xen/iommu.h> +#include <asm/mem_event.h> +#include <public/mem_event.h> +#include <xen/event.h> /* Debugging and auditing of the P2M code? */ #define P2M_AUDIT 0 @@ -2297,6 +2301,163 @@ clear_mmio_p2m_entry(struct domain *d, u return rc; } +int p2m_mem_paging_nominate(struct domain *d, unsigned long gfn) +{ + struct page_info *page; + p2m_type_t p2mt; + mfn_t mfn; + int ret; + + mfn = gfn_to_mfn(d, gfn, &p2mt); + + /* Check if mfn is valid */ + ret = -EINVAL; + if ( !mfn_valid(mfn) ) + goto out; + + /* Check p2m type */ + ret = -EAGAIN; + if ( !p2m_is_pageable(p2mt) ) + goto out; + + /* Check for io memory page */ + if ( is_iomem_page(mfn_x(mfn)) ) + goto out; + + /* Check page count and type */ + page = mfn_to_page(mfn); + if ( (page->count_info & (PGC_count_mask | PGC_allocated)) != + (1 | PGC_allocated) ) + goto out; + + if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_none ) + goto out; + + /* Fix p2m entry */ + p2m_lock(d->arch.p2m); + set_p2m_entry(d, gfn, mfn, 0, p2m_ram_paging_out); + p2m_unlock(d->arch.p2m); + + ret = 0; + + out: + return ret; +} + +int p2m_mem_paging_evict(struct domain *d, unsigned long gfn) +{ + struct page_info *page; + p2m_type_t p2mt; + mfn_t mfn; + + /* Get mfn */ + mfn = gfn_to_mfn(d, gfn, &p2mt); + if ( unlikely(!mfn_valid(mfn)) ) + return -EINVAL; + + if ( (p2mt == p2m_ram_paged) || (p2mt == p2m_ram_paging_in) || + (p2mt == p2m_ram_paging_in_start) ) + return -EINVAL; + + /* Get the page so it doesn't get modified under Xen's feet */ + page = mfn_to_page(mfn); + if ( unlikely(!get_page(page, d)) ) + return -EINVAL; + + /* Decrement guest domain's ref count of the page */ + if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) + put_page(page); + + /* Remove mapping from p2m table */ + p2m_lock(d->arch.p2m); + set_p2m_entry(d, gfn, _mfn(PAGING_MFN), 0, p2m_ram_paged); + p2m_unlock(d->arch.p2m); + + /* Put the page back so it gets freed */ + put_page(page); + + return 0; +} + +void p2m_mem_paging_populate(struct domain *d, unsigned long gfn) +{ + struct vcpu *v = current; + mem_event_request_t req; + p2m_type_t p2mt; + + memset(&req, 0, sizeof(req)); + + /* Check that there's space on the ring for this request */ + if ( mem_event_check_ring(d) ) + return; + + /* Fix p2m mapping */ + /* XXX: It seems inefficient to have this here, as it's only needed + * in one case (ept guest accessing paging out page) */ + gfn_to_mfn(d, gfn, &p2mt); + if ( p2mt != p2m_ram_paging_out ) + { + p2m_lock(d->arch.p2m); + set_p2m_entry(d, gfn, _mfn(PAGING_MFN), 0, p2m_ram_paging_in_start); + p2m_unlock(d->arch.p2m); + } + + /* Pause domain */ + if ( v->domain->domain_id == d->domain_id ) + { + vcpu_pause_nosync(v); + req.flags |= MEM_EVENT_FLAG_PAUSED; + } + + /* Send request to pager */ + req.gfn = gfn; + req.p2mt = p2mt; + req.vcpu_id = v->vcpu_id; + + mem_event_put_request(d, &req); +} + +int p2m_mem_paging_prep(struct domain *d, unsigned long gfn) +{ + struct page_info *page; + + /* Get a free page */ + page = alloc_domheap_page(d, 0); + if ( unlikely(page == NULL) ) + return -EINVAL; + + /* Fix p2m mapping */ + p2m_lock(d->arch.p2m); + set_p2m_entry(d, gfn, page_to_mfn(page), 0, p2m_ram_paging_in); + p2m_unlock(d->arch.p2m); + + return 0; +} + +void p2m_mem_paging_resume(struct domain *d) +{ + mem_event_response_t rsp; + p2m_type_t p2mt; + mfn_t mfn; + + /* Pull the response off the ring */ + mem_event_get_response(d, &rsp); + + /* Fix p2m entry */ + mfn = gfn_to_mfn(d, rsp.gfn, &p2mt); + p2m_lock(d->arch.p2m); + set_p2m_entry(d, rsp.gfn, mfn, 0, p2m_ram_rw); + p2m_unlock(d->arch.p2m); + + /* Unpause domain */ + if ( rsp.flags & MEM_EVENT_FLAG_PAUSED ) + vcpu_unpause(d->vcpu[rsp.vcpu_id]); + + /* Unpause any domains that were paused because the ring was full */ + mem_event_unpause_vcpus(d); +} + + /* * Local variables: * mode: C diff -r c9fb3c514f65 -r 01037b222d74 xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Thu Dec 17 06:27:55 2009 +0000 +++ b/xen/include/asm-x86/p2m.h Thu Dec 17 06:27:55 2009 +0000 @@ -75,6 +75,11 @@ typedef enum { #ifdef's everywhere else. */ p2m_grant_map_rw = 7, /* Read/write grant mapping */ p2m_grant_map_ro = 8, /* Read-only grant mapping */ + + p2m_ram_paging_out = 9, /* Memory that is being paged out */ + p2m_ram_paged = 10, /* Memory that has been paged out */ + p2m_ram_paging_in = 11, /* Memory that is being paged in */ + p2m_ram_paging_in_start = 12, /* Memory that is being paged in */ } p2m_type_t; typedef enum { @@ -87,9 +92,13 @@ typedef enum { #define p2m_to_mask(_t) (1UL << (_t)) /* RAM types, which map to real machine frames */ -#define P2M_RAM_TYPES (p2m_to_mask(p2m_ram_rw) \ - | p2m_to_mask(p2m_ram_logdirty) \ - | p2m_to_mask(p2m_ram_ro)) +#define P2M_RAM_TYPES (p2m_to_mask(p2m_ram_rw) \ + | p2m_to_mask(p2m_ram_logdirty) \ + | p2m_to_mask(p2m_ram_ro) \ + | p2m_to_mask(p2m_ram_paging_out) \ + | p2m_to_mask(p2m_ram_paged) \ + | p2m_to_mask(p2m_ram_paging_in_start) \ + | p2m_to_mask(p2m_ram_paging_in)) /* Grant mapping types, which map to a real machine frame in another * VM */ @@ -106,6 +115,16 @@ typedef enum { | p2m_to_mask(p2m_grant_map_ro) ) #define P2M_MAGIC_TYPES (p2m_to_mask(p2m_populate_on_demand)) + +/* Pageable types */ +#define P2M_PAGEABLE_TYPES (p2m_to_mask(p2m_ram_rw)) + +#define P2M_PAGING_TYPES (p2m_to_mask(p2m_ram_paging_out) \ + | p2m_to_mask(p2m_ram_paged) \ + | p2m_to_mask(p2m_ram_paging_in_start) \ + | p2m_to_mask(p2m_ram_paging_in)) + +#define P2M_PAGED_TYPES (p2m_to_mask(p2m_ram_paged)) /* Useful predicates */ #define p2m_is_ram(_t) (p2m_to_mask(_t) & P2M_RAM_TYPES) @@ -118,11 +137,15 @@ typedef enum { implementations, there's no way of synchronising against that. */ #define p2m_is_valid(_t) (p2m_to_mask(_t) & (P2M_RAM_TYPES | P2M_MMIO_TYPES)) #define p2m_has_emt(_t) (p2m_to_mask(_t) & (P2M_RAM_TYPES | p2m_to_mask(p2m_mmio_direct))) +#define p2m_is_pageable(_t) (p2m_to_mask(_t) & P2M_PAGEABLE_TYPES) +#define p2m_is_paging(_t) (p2m_to_mask(_t) & P2M_PAGING_TYPES) +#define p2m_is_paged(_t) (p2m_to_mask(_t) & P2M_PAGED_TYPES) /* Populate-on-demand */ #define POPULATE_ON_DEMAND_MFN (1<<9) #define POD_PAGE_ORDER 9 +#define PAGING_MFN INVALID_MFN struct p2m_domain { /* Lock that protects updates to the p2m */ @@ -369,6 +392,17 @@ int set_mmio_p2m_entry(struct domain *d, int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn); int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn); +/* Check if a nominated gfn is valid to be paged out */ +int p2m_mem_paging_nominate(struct domain *d, unsigned long gfn); +/* Evict a frame */ +int p2m_mem_paging_evict(struct domain *d, unsigned long gfn); +/* Start populating a paged out frame */ +void p2m_mem_paging_populate(struct domain *d, unsigned long gfn); +/* Prepare the p2m for paging a frame in */ +int p2m_mem_paging_prep(struct domain *d, unsigned long gfn); +/* Resume normal operation (in case a domain was paused) */ +void p2m_mem_paging_resume(struct domain *d); + #endif /* _XEN_P2M_H */ /* _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |