Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 00/12] xenpaging changes for xen-unstable
Here are some changes for xenpaging in xen-unstable. New to this series since my last post are patch 1 to 5. They are likely non-controversial and could be applied. Patches 6 and 7 are required to maintain the machine_to_phys_mapping[] array properly. Unless there are objections to the deallocation part, they could be applied. Patch 8 could be applied as well. All other changes are not ready yet for inclusion. As it stands right now, a guest will hang hard with xenpaging once the balloon driver is loaded in the guest. Its not clear what the issue is, no memory_op hypercall has been issued yet. xm vcpu-list indicates the guest makes no progress. I will debug this further. Olaf _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 01/12] xenpaging: remove domain_id and mfn from struct xenpaging_victim
Remove unused member ''mfn'' from struct xenpaging_victim. xenpaging operates on a single guest, so it needs only a single domain_id. Remove domain_id from struct xenpaging_victim and use the one from paging->mem_event where needed. Its not used in the policy. This saves 4MB runtime data with a 1GB pagefile. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- tools/xenpaging/policy.h | 7 +++---- tools/xenpaging/policy_default.c | 10 +++------- tools/xenpaging/xenpaging.c | 26 ++++++++++++-------------- tools/xenpaging/xenpaging.h | 4 ---- 4 files changed, 18 insertions(+), 29 deletions(-) --- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/policy.h +++ xen-unstable.hg-4.1.22694/tools/xenpaging/policy.h @@ -29,10 +29,9 @@ int policy_init(xenpaging_t *paging); -int policy_choose_victim(xenpaging_t *paging, domid_t domain_id, - xenpaging_victim_t *victim); -void policy_notify_paged_out(domid_t domain_id, unsigned long gfn); -void policy_notify_paged_in(domid_t domain_id, unsigned long gfn); +int policy_choose_victim(xenpaging_t *paging, xenpaging_victim_t *victim); +void policy_notify_paged_out(unsigned long gfn); +void policy_notify_paged_in(unsigned long gfn); #endif // __XEN_PAGING_POLICY_H__ --- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/policy_default.c +++ xen-unstable.hg-4.1.22694/tools/xenpaging/policy_default.c @@ -67,16 +67,12 @@ int policy_init(xenpaging_t *paging) return rc; } -int policy_choose_victim(xenpaging_t *paging, domid_t domain_id, - xenpaging_victim_t *victim) +int policy_choose_victim(xenpaging_t *paging, xenpaging_victim_t *victim) { xc_interface *xch = paging->xc_handle; unsigned long wrap = current_gfn; ASSERT(victim != NULL); - /* Domain to pick on */ - victim->domain_id = domain_id; - do { current_gfn++; @@ -96,13 +92,13 @@ int policy_choose_victim(xenpaging_t *pa return 0; } -void policy_notify_paged_out(domid_t domain_id, unsigned long gfn) +void policy_notify_paged_out(unsigned long gfn) { set_bit(gfn, bitmap); clear_bit(gfn, unconsumed); } -void policy_notify_paged_in(domid_t domain_id, unsigned long gfn) +void policy_notify_paged_in(unsigned long gfn) { unsigned long old_gfn = mru[i_mru & (MRU_SIZE - 1)]; --- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/xenpaging.c +++ xen-unstable.hg-4.1.22694/tools/xenpaging/xenpaging.c @@ -171,7 +171,7 @@ xenpaging_t *xenpaging_init(domid_t doma goto err; } - rc = xc_get_platform_info(xch, domain_id, + rc = xc_get_platform_info(xch, paging->mem_event.domain_id, paging->platform_info); if ( rc != 1 ) { @@ -187,7 +187,7 @@ xenpaging_t *xenpaging_init(domid_t doma goto err; } - rc = xc_domain_getinfolist(xch, domain_id, 1, + rc = xc_domain_getinfolist(xch, paging->mem_event.domain_id, 1, paging->domain_info); if ( rc != 1 ) { @@ -348,7 +348,7 @@ int xenpaging_evict_page(xenpaging_t *pa /* Map page */ gfn = victim->gfn; ret = -EFAULT; - page = xc_map_foreign_pages(xch, victim->domain_id, + page = xc_map_foreign_pages(xch, paging->mem_event.domain_id, PROT_READ | PROT_WRITE, &gfn, 1); if ( page == NULL ) { @@ -380,7 +380,7 @@ int xenpaging_evict_page(xenpaging_t *pa } /* Notify policy of page being paged out */ - policy_notify_paged_out(paging->mem_event.domain_id, victim->gfn); + policy_notify_paged_out(victim->gfn); out: return ret; @@ -397,7 +397,7 @@ static int xenpaging_resume_page(xenpagi /* Notify policy of page being paged in */ if ( notify_policy ) - policy_notify_paged_in(paging->mem_event.domain_id, rsp->gfn); + policy_notify_paged_in(rsp->gfn); /* Tell Xen page is ready */ ret = xc_mem_paging_resume(paging->xc_handle, paging->mem_event.domain_id, @@ -464,7 +464,7 @@ static int xenpaging_populate_page(xenpa return ret; } -static int evict_victim(xenpaging_t *paging, domid_t domain_id, +static int evict_victim(xenpaging_t *paging, xenpaging_victim_t *victim, int fd, int i) { xc_interface *xch = paging->xc_handle; @@ -473,7 +473,7 @@ static int evict_victim(xenpaging_t *pag do { - ret = policy_choose_victim(paging, domain_id, victim); + ret = policy_choose_victim(paging, victim); if ( ret != 0 ) { if ( ret != -ENOSPC ) @@ -486,14 +486,13 @@ static int evict_victim(xenpaging_t *pag ret = -EINTR; goto out; } - ret = xc_mem_paging_nominate(xch, - paging->mem_event.domain_id, victim->gfn); + ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, victim->gfn); if ( ret == 0 ) ret = xenpaging_evict_page(paging, victim, fd, i); else { if ( j++ % 1000 == 0 ) - if ( xc_mem_paging_flush_ioemu_cache(domain_id) ) + if ( xc_mem_paging_flush_ioemu_cache(paging->mem_event.domain_id) ) ERROR("Error flushing ioemu cache"); } } @@ -578,7 +577,7 @@ int main(int argc, char *argv[]) memset(victims, 0, sizeof(xenpaging_victim_t) * num_pages); for ( i = 0; i < num_pages; i++ ) { - rc = evict_victim(paging, domain_id, &victims[i], fd, i); + rc = evict_victim(paging, &victims[i], fd, i); if ( rc == -ENOSPC ) break; if ( rc == -EINTR ) @@ -619,8 +618,7 @@ int main(int argc, char *argv[]) /* Find where in the paging file to read from */ for ( i = 0; i < num_pages; i++ ) { - if ( (victims[i].domain_id == paging->mem_event.domain_id) && - (victims[i].gfn == req.gfn) ) + if ( victims[i].gfn == req.gfn ) break; } @@ -652,7 +650,7 @@ int main(int argc, char *argv[]) } /* Evict a new page to replace the one we just paged in */ - evict_victim(paging, domain_id, &victims[i], fd, i); + evict_victim(paging, &victims[i], fd, i); } else { --- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/xenpaging.h +++ xen-unstable.hg-4.1.22694/tools/xenpaging/xenpaging.h @@ -49,12 +49,8 @@ typedef struct xenpaging { typedef struct xenpaging_victim { - /* the domain to evict a page from */ - domid_t domain_id; /* the gfn of the page to evict */ unsigned long gfn; - /* the mfn of evicted page */ - unsigned long mfn; } xenpaging_victim_t; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 02/12] xenpaging: specify policy mru_size at runtime
The environment variable XENPAGING_POLICY_MRU_SIZE will change the mru_size in the policy at runtime. Specifying the mru_size at runtime allows the admin to keep more pages in memory so guests can make more progress. Its also good for development to reduce the value to put more pressure on the paging related code paths. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- Note: some work is still required to actually get the value into the environment of the process. Maybe it will become an config option at some point. tools/xenpaging/policy_default.c | 23 ++++++++++++++++++----- tools/xenpaging/xenpaging.c | 8 ++++++++ tools/xenpaging/xenpaging.h | 1 + 3 files changed, 27 insertions(+), 5 deletions(-) --- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/policy_default.c +++ xen-unstable.hg-4.1.22571/tools/xenpaging/policy_default.c @@ -26,11 +26,12 @@ #include "policy.h" -#define MRU_SIZE (1024 * 16) +#define DEFAULT_MRU_SIZE (1024 * 16) -static unsigned long mru[MRU_SIZE]; +static unsigned long *mru; static unsigned int i_mru; +static unsigned int mru_size; static unsigned long *bitmap; static unsigned long *unconsumed; static unsigned long current_gfn; @@ -57,7 +58,19 @@ int policy_init(xenpaging_t *paging) max_pages = paging->domain_info->max_pages; /* Initialise MRU list of paged in pages */ - for ( i = 0; i < MRU_SIZE; i++ ) + if ( paging->policy_mru_size > 0 ) + mru_size = paging->policy_mru_size; + else + mru_size = DEFAULT_MRU_SIZE; + + mru = malloc(sizeof(*mru) * mru_size); + if ( mru == NULL ) + { + rc = -ENOMEM; + goto out; + } + + for ( i = 0; i < mru_size; i++ ) mru[i] = INVALID_MFN; /* Don''t page out page 0 */ @@ -100,12 +113,12 @@ void policy_notify_paged_out(unsigned lo void policy_notify_paged_in(unsigned long gfn) { - unsigned long old_gfn = mru[i_mru & (MRU_SIZE - 1)]; + unsigned long old_gfn = mru[i_mru & (mru_size - 1)]; if ( old_gfn != INVALID_MFN ) clear_bit(old_gfn, bitmap); - mru[i_mru & (MRU_SIZE - 1)] = gfn; + mru[i_mru & (mru_size - 1)] = gfn; i_mru++; } --- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/xenpaging.c +++ xen-unstable.hg-4.1.22571/tools/xenpaging/xenpaging.c @@ -78,6 +78,7 @@ xenpaging_t *xenpaging_init(domid_t doma xenpaging_t *paging; xc_interface *xch; xentoollog_logger *dbg = NULL; + char *p; int rc; if ( getenv("XENPAGING_DEBUG") ) @@ -92,6 +93,13 @@ xenpaging_t *xenpaging_init(domid_t doma paging = malloc(sizeof(xenpaging_t)); memset(paging, 0, sizeof(xenpaging_t)); + p = getenv("XENPAGING_POLICY_MRU_SIZE"); + if ( p && *p ) + { + paging->policy_mru_size = atoi(p); + DPRINTF("Setting policy mru_size to %d\n", paging->policy_mru_size); + } + /* Open connection to xen */ paging->xc_handle = xch; --- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/xenpaging.h +++ xen-unstable.hg-4.1.22571/tools/xenpaging/xenpaging.h @@ -45,6 +45,7 @@ typedef struct xenpaging { unsigned long *bitmap; mem_event_t mem_event; + int policy_mru_size; } xenpaging_t; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 03/12] xenpaging: mkdir /var/lib/xen/xenpaging during make install
pagefiles go to /var/lib/xen/xenpaging directory, create this directory during make install Signed-off-by: Olaf Hering <olaf@aepfle.de> --- tools/xenpaging/Makefile | 1 + 1 file changed, 1 insertion(+) --- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/Makefile +++ xen-unstable.hg-4.1.22571/tools/xenpaging/Makefile @@ -27,6 +27,7 @@ xenpaging: $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) install: all + $(INSTALL_DIR) $(DESTDIR)/var/lib/xen/xenpaging $(INSTALL_DIR) $(DESTDIR)$(SBINDIR) $(INSTALL_PROG) $(IBINS) $(DESTDIR)$(SBINDIR) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 04/12] xenpaging: print page-in/page-out progress
Now that DPRINTF is triggered only when the environment variable XENPAGING_DEBUG is found, make such a debug session actually useful by printing the entire page-out/page-in process. The ''Got event from Xen'' message alone is not helpful. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- tools/xenpaging/xenpaging.c | 2 ++ 1 file changed, 2 insertions(+) --- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/xenpaging.c +++ xen-unstable.hg-4.1.22571/tools/xenpaging/xenpaging.c @@ -387,6 +387,7 @@ int xenpaging_evict_page(xenpaging_t *pa goto out; } + DPRINTF("evict_page > gfn %lx pageslot %d\n", victim->gfn, i); /* Notify policy of page being paged out */ policy_notify_paged_out(victim->gfn); @@ -427,6 +428,7 @@ static int xenpaging_populate_page(xenpa unsigned char oom = 0; _gfn = *gfn; + DPRINTF("populate_page < gfn %lx pageslot %d\n", _gfn, i); do { /* Tell Xen to allocate a page for the domain */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 05/12] xenpaging: make three functions static
xenpaging_init(), xenpaging_teardown() and xenpaging_evict_page() are only used in file scope, so they can be marked static. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- tools/xenpaging/xenpaging.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) --- xen-unstable.hg-4.1.22697.orig/tools/xenpaging/xenpaging.c +++ xen-unstable.hg-4.1.22697/tools/xenpaging/xenpaging.c @@ -73,7 +73,7 @@ static void *init_page(void) return NULL; } -xenpaging_t *xenpaging_init(domid_t domain_id) +static xenpaging_t *xenpaging_init(domid_t domain_id) { xenpaging_t *paging; xc_interface *xch; @@ -251,7 +251,7 @@ xenpaging_t *xenpaging_init(domid_t doma return NULL; } -int xenpaging_teardown(xenpaging_t *paging) +static int xenpaging_teardown(xenpaging_t *paging) { int rc; xc_interface *xch; @@ -343,7 +343,7 @@ static int put_response(mem_event_t *mem return 0; } -int xenpaging_evict_page(xenpaging_t *paging, +static int xenpaging_evict_page(xenpaging_t *paging, xenpaging_victim_t *victim, int fd, int i) { xc_interface *xch = paging->xc_handle; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
The machine_to_phys_mapping[] array needs updating during page deallocation. If that page is allocated again, a call to get_gpfn_from_mfn() will still return an old gfn from another guest. This will cause trouble because this gfn number has no or different meaning in the context of the current guest. This happens when the entire guest ram is paged-out before xen_vga_populate_vram() runs. Then XENMEM_populate_physmap is called with gfn 0xff000. A new page is allocated with alloc_domheap_pages. This new page does not have a gfn yet. However, in guest_physmap_add_entry() the passed mfn maps still to an old gfn (perhaps from another old guest). This old gfn is in paged-out state in this guests context and has no mfn anymore. As a result, the ASSERT() triggers because p2m_is_ram() is true for p2m_ram_paging* types. If the machine_to_phys_mapping[] array is updated properly, both loops in guest_physmap_add_entry() turn into no-ops for the new page and the mfn/gfn mapping will be done at the end of the function. If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn, get_gpfn_from_mfn() will return an appearently valid gfn. As a result, guest_physmap_remove_page() is called. The ASSERT in p2m_remove_page triggers because the passed mfn does not match the old mfn for the passed gfn. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- xen/common/page_alloc.c | 6 ++++++ 1 file changed, 6 insertions(+) --- xen-unstable.hg-4.1.22571.orig/xen/common/page_alloc.c +++ xen-unstable.hg-4.1.22571/xen/common/page_alloc.c @@ -1200,9 +1200,15 @@ void free_domheap_pages(struct page_info { int i, drop_dom_ref; struct domain *d = page_get_owner(pg); + unsigned long mfn; ASSERT(!in_irq()); + /* this page is not a gfn anymore */ + mfn = page_to_mfn(pg); + for ( i = 0; i < (1 << order); i++ ) + set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY); + if ( unlikely(is_xen_heap_page(pg)) ) { /* NB. May recursively lock from relinquish_memory(). */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 07/12] xenpaging: update machine_to_phys_mapping[] during page-in
Update the machine_to_phys_mapping[] array during page-in. The gfn is now at a different page and the array has still INVALID_M2P_ENTRY in the index. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- xen/arch/x86/mm/p2m.c | 1 + 1 file changed, 1 insertion(+) --- xen-unstable.hg-4.1.22694.orig/xen/arch/x86/mm/p2m.c +++ xen-unstable.hg-4.1.22694/xen/arch/x86/mm/p2m.c @@ -2850,6 +2850,7 @@ void p2m_mem_paging_resume(struct p2m_do mfn = gfn_to_mfn(p2m, rsp.gfn, &p2mt); p2m_lock(p2m); set_p2m_entry(p2m, rsp.gfn, mfn, 0, p2m_ram_rw, p2m->default_access); + set_gpfn_from_mfn(mfn_x(mfn), gfn); audit_p2m(p2m, 1); p2m_unlock(p2m); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page
Simply drop paged-pages in guest_remove_page(), and notify xenpaging to drop its reference to the gfn. If the ring is full, the page will remain in paged-out state in xenpaging. This is not an issue, it just means this gfn will not be nominated again. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- v3: send one-way notification to pager to release page use new mem_event_check_ring() feature to not pause vcpu when ring is full v2: resume dropped page to unpause vcpus tools/xenpaging/xenpaging.c | 39 ++++++++++++++++++++------------ xen/arch/x86/mm/p2m.c | 49 ++++++++++++++++++++++++++++++----------- xen/common/memory.c | 6 +++++ xen/include/asm-x86/p2m.h | 4 +++ xen/include/public/mem_event.h | 1 5 files changed, 72 insertions(+), 27 deletions(-) --- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/xenpaging.c +++ xen-unstable.hg-4.1.22694/tools/xenpaging/xenpaging.c @@ -638,25 +638,34 @@ int main(int argc, char *argv[]) goto out; } - /* Populate the page */ - rc = xenpaging_populate_page(paging, &req.gfn, fd, i); - if ( rc != 0 ) + if ( req.flags & MEM_EVENT_FLAG_DROP_PAGE ) { - ERROR("Error populating page"); - goto out; + DPRINTF("drop_page ^ gfn %"PRIx64" pageslot %d\n", req.gfn, i); + /* Notify policy of page being dropped */ + policy_notify_paged_in(req.gfn); } + else + { + /* Populate the page */ + rc = xenpaging_populate_page(paging, &req.gfn, fd, i); + if ( rc != 0 ) + { + ERROR("Error populating page"); + goto out; + } - /* Prepare the response */ - rsp.gfn = req.gfn; - rsp.p2mt = req.p2mt; - rsp.vcpu_id = req.vcpu_id; - rsp.flags = req.flags; + /* Prepare the response */ + rsp.gfn = req.gfn; + rsp.p2mt = req.p2mt; + rsp.vcpu_id = req.vcpu_id; + rsp.flags = req.flags; - rc = xenpaging_resume_page(paging, &rsp, 1); - if ( rc != 0 ) - { - ERROR("Error resuming page"); - goto out; + rc = xenpaging_resume_page(paging, &rsp, 1); + if ( rc != 0 ) + { + ERROR("Error resuming page"); + goto out; + } } /* Evict a new page to replace the one we just paged in */ --- xen-unstable.hg-4.1.22694.orig/xen/arch/x86/mm/p2m.c +++ xen-unstable.hg-4.1.22694/xen/arch/x86/mm/p2m.c @@ -2211,12 +2211,15 @@ p2m_remove_page(struct p2m_domain *p2m, P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn); - for ( i = 0; i < (1UL << page_order); i++ ) + if ( mfn_valid(_mfn(mfn)) ) { - mfn_return = p2m->get_entry(p2m, gfn + i, &t, &a, p2m_query); - if ( !p2m_is_grant(t) ) - set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY); - ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) ); + for ( i = 0; i < (1UL << page_order); i++ ) + { + mfn_return = p2m->get_entry(p2m, gfn + i, &t, &a, p2m_query); + if ( !p2m_is_grant(t) ) + set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY); + ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) ); + } } set_p2m_entry(p2m, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid, p2m->default_access); } @@ -2772,6 +2775,25 @@ int p2m_mem_paging_evict(struct p2m_doma return 0; } +void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn) +{ + struct vcpu *v = current; + mem_event_request_t req; + struct domain *d = p2m->domain; + + /* Check that there''s space on the ring for this request */ + if ( mem_event_check_ring(d) == 0) + { + /* Send release notification to pager */ + memset(&req, 0, sizeof(req)); + req.flags |= MEM_EVENT_FLAG_DROP_PAGE; + req.gfn = gfn; + req.vcpu_id = v->vcpu_id; + + mem_event_put_request(d, &req); + } +} + void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn) { struct vcpu *v = current; @@ -2846,13 +2868,16 @@ void p2m_mem_paging_resume(struct p2m_do /* Pull the response off the ring */ mem_event_get_response(d, &rsp); - /* Fix p2m entry */ - mfn = gfn_to_mfn(p2m, rsp.gfn, &p2mt); - p2m_lock(p2m); - set_p2m_entry(p2m, rsp.gfn, mfn, 0, p2m_ram_rw, p2m->default_access); - set_gpfn_from_mfn(mfn_x(mfn), gfn); - audit_p2m(p2m, 1); - p2m_unlock(p2m); + /* Fix p2m entry if the page was not dropped */ + if ( !(rsp.flags & MEM_EVENT_FLAG_DROP_PAGE) ) + { + mfn = gfn_to_mfn(p2m, rsp.gfn, &p2mt); + p2m_lock(p2m); + set_p2m_entry(p2m, rsp.gfn, mfn, 0, p2m_ram_rw, p2m->default_access); + set_gpfn_from_mfn(mfn_x(mfn), rsp.gfn); + audit_p2m(p2m, 1); + p2m_unlock(p2m); + } /* Unpause domain */ if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED ) --- xen-unstable.hg-4.1.22694.orig/xen/common/memory.c +++ xen-unstable.hg-4.1.22694/xen/common/memory.c @@ -163,6 +163,12 @@ int guest_remove_page(struct domain *d, #ifdef CONFIG_X86 mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(d), gmfn, &p2mt)); + if ( unlikely(p2m_is_paging(p2mt)) ) + { + guest_physmap_remove_page(d, gmfn, mfn, 0); + p2m_mem_paging_drop_page(p2m_get_hostp2m(d), gmfn); + return 1; + } #else mfn = gmfn_to_mfn(d, gmfn); #endif --- xen-unstable.hg-4.1.22694.orig/xen/include/asm-x86/p2m.h +++ xen-unstable.hg-4.1.22694/xen/include/asm-x86/p2m.h @@ -511,6 +511,8 @@ int set_shared_p2m_entry(struct p2m_doma int p2m_mem_paging_nominate(struct p2m_domain *p2m, unsigned long gfn); /* Evict a frame */ int p2m_mem_paging_evict(struct p2m_domain *p2m, unsigned long gfn); +/* Tell xenpaging to drop a paged out frame */ +void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn); /* Start populating a paged out frame */ void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn); /* Prepare the p2m for paging a frame in */ @@ -518,6 +520,8 @@ int p2m_mem_paging_prep(struct p2m_domai /* Resume normal operation (in case a domain was paused) */ void p2m_mem_paging_resume(struct p2m_domain *p2m); #else +static inline void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn) +{ } static inline void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn) { } #endif --- xen-unstable.hg-4.1.22694.orig/xen/include/public/mem_event.h +++ xen-unstable.hg-4.1.22694/xen/include/public/mem_event.h @@ -33,6 +33,7 @@ /* Memory event flags */ #define MEM_EVENT_FLAG_VCPU_PAUSED (1 << 0) +#define MEM_EVENT_FLAG_DROP_PAGE (1 << 1) /* Reasons for the memory event request */ #define MEM_EVENT_REASON_UNKNOWN 0 /* typical reason */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 09/12] xenpaging: prevent page-out of gfn 0x80
Add a workaround for missing handling of paged-out pages during BIOS startup. For some reason, only gfn 0x80 is affected. (XEN) HVM3: HVM Loader (XEN) traps.c:649:d3 Bad GMFN 80 (MFN ffffffffff) to MSR 40000000 (XEN) HVM3: Detected Xen v4.1 (XEN) HVM3: HVMLoader bug at util.c:604 (XEN) hvm.c:1085:d3 Triple fault on VCPU0 - invoking HVM system reset. (XEN) HVM4: HVM Loader (XEN) traps.c:649:d4 Bad GMFN 80 (MFN ffffffffff) to MSR 40000000 (XEN) io.c:194:d4 MMIO emulation failed @ 0018:9ffff: 00 6a 10 80 c4 82 (XEN) hvm.c:1085:d4 Triple fault on VCPU0 - invoking HVM system reset. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- Another part of the bugfix is the missing p2m_mem_paging_populate() call in gfn_to_mfn() tools/xenpaging/policy_default.c | 3 +++ 1 file changed, 3 insertions(+) --- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/policy_default.c +++ xen-unstable.hg-4.1.22571/tools/xenpaging/policy_default.c @@ -76,6 +76,9 @@ int policy_init(xenpaging_t *paging) /* Don''t page out page 0 */ set_bit(0, bitmap); + /* this is the trap page, disabled for the time being */ + set_bit(0x80, bitmap); + out: return rc; } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 10/12] xenpaging: handle HVMCOPY_gfn_paged_out in copy_from/to_user
copy_from_user_hvm can fail when __hvm_copy returns HVMCOPY_gfn_paged_out for a referenced gfn, for example during guests pagetable walk. This has to be handled in some way. For the time being, return -EAGAIN for the most common case (xen_balloon driver crashing in guest) until the recently added waitqueues will be used. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- xen/arch/x86/hvm/hvm.c | 4 ++++ xen/common/memory.c | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) --- xen-unstable.hg-4.1.22697.orig/xen/arch/x86/hvm/hvm.c +++ xen-unstable.hg-4.1.22697/xen/arch/x86/hvm/hvm.c @@ -2154,6 +2154,8 @@ unsigned long copy_to_user_hvm(void *to, rc = hvm_copy_to_guest_virt_nofault((unsigned long)to, (void *)from, len, 0); + if ( unlikely(rc == HVMCOPY_gfn_paged_out) ) + return -EAGAIN; return rc ? len : 0; /* fake a copy_to_user() return code */ } @@ -2171,6 +2173,8 @@ unsigned long copy_from_user_hvm(void *t #endif rc = hvm_copy_from_guest_virt_nofault(to, (unsigned long)from, len, 0); + if ( unlikely(rc == HVMCOPY_gfn_paged_out) ) + return -EAGAIN; return rc ? len : 0; /* fake a copy_from_user() return code */ } --- xen-unstable.hg-4.1.22697.orig/xen/common/memory.c +++ xen-unstable.hg-4.1.22697/xen/common/memory.c @@ -48,6 +48,7 @@ static void increase_reservation(struct { struct page_info *page; unsigned long i; + unsigned long ctg_ret; xen_pfn_t mfn; struct domain *d = a->domain; @@ -81,8 +82,13 @@ static void increase_reservation(struct if ( !guest_handle_is_null(a->extent_list) ) { mfn = page_to_mfn(page); - if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) ) + ctg_ret = __copy_to_guest_offset(a->extent_list, i, &mfn, 1); + if ( unlikely(ctg_ret) ) + { + if ( (long)ctg_ret == -EAGAIN ) + a->preempted = 1; goto out; + } } } @@ -94,6 +100,7 @@ static void populate_physmap(struct memo { struct page_info *page; unsigned long i, j; + unsigned long cftg_ret; xen_pfn_t gpfn, mfn; struct domain *d = a->domain; @@ -112,8 +119,13 @@ static void populate_physmap(struct memo goto out; } - if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) ) + cftg_ret = __copy_from_guest_offset(&gpfn, a->extent_list, i, 1); + if ( unlikely(cftg_ret) ) + { + if ( (long)cftg_ret == -EAGAIN ) + a->preempted = 1; goto out; + } if ( a->memflags & MEMF_populate_on_demand ) { @@ -143,8 +155,13 @@ static void populate_physmap(struct memo set_gpfn_from_mfn(mfn + j, gpfn + j); /* Inform the domain of the new page''s machine address. */ - if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) ) + cftg_ret = __copy_to_guest_offset(a->extent_list, i, &mfn, 1); + if ( unlikely(cftg_ret) ) + { + if ( (long)cftg_ret == -EAGAIN ) + a->preempted = 1; goto out; + } } } } @@ -213,6 +230,7 @@ int guest_remove_page(struct domain *d, static void decrease_reservation(struct memop_args *a) { unsigned long i, j; + unsigned long cfg_ret; xen_pfn_t gmfn; if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done, @@ -227,8 +245,13 @@ static void decrease_reservation(struct goto out; } - if ( unlikely(__copy_from_guest_offset(&gmfn, a->extent_list, i, 1)) ) + cfg_ret = __copy_from_guest_offset(&gmfn, a->extent_list, i, 1); + if ( unlikely(cfg_ret) ) + { + if ( (long)cfg_ret == -EAGAIN ) + a->preempted = 1; goto out; + } if ( tb_init_done ) { @@ -509,6 +532,7 @@ long do_memory_op(unsigned long cmd, XEN int rc, op; unsigned int address_bits; unsigned long start_extent; + unsigned long cfg_ret; struct xen_memory_reservation reservation; struct memop_args args; domid_t domid; @@ -522,8 +546,13 @@ long do_memory_op(unsigned long cmd, XEN case XENMEM_populate_physmap: start_extent = cmd >> MEMOP_EXTENT_SHIFT; - if ( copy_from_guest(&reservation, arg, 1) ) + cfg_ret = copy_from_guest(&reservation, arg, 1); + if ( unlikely(cfg_ret) ) + { + if ( (long)cfg_ret == -EAGAIN ) + return hypercall_create_continuation(__HYPERVISOR_memory_op, "lh", cmd, arg); return start_extent; + } /* Is size too large for us to encode a continuation? */ if ( reservation.nr_extents > (ULONG_MAX >> MEMOP_EXTENT_SHIFT) ) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 11/12] xenpaging: start xenpaging via config option
Start xenpaging via config option. TODO: add config option for different pagefile directory TODO: add libxl support TODO: parse config values like 42K, 42M, 42G, 42% Signed-off-by: Olaf Hering <olaf@aepfle.de> --- v3: move debug for stopping xenpaging to destroyXenPaging v2: unlink logfile instead of truncating it. allows hardlinking for further inspection tools/examples/xmexample.hvm | 3 + tools/python/README.XendConfig | 1 tools/python/README.sxpcfg | 1 tools/python/xen/xend/XendConfig.py | 3 + tools/python/xen/xend/XendDomainInfo.py | 5 + tools/python/xen/xend/image.py | 87 ++++++++++++++++++++++++++++++++ tools/python/xen/xm/create.py | 5 + tools/python/xen/xm/xenapi_create.py | 1 8 files changed, 106 insertions(+) --- xen-unstable.hg-4.1.22571.orig/tools/examples/xmexample.hvm +++ xen-unstable.hg-4.1.22571/tools/examples/xmexample.hvm @@ -127,6 +127,9 @@ disk = [ ''file:/var/images/min-el3-i386. # Device Model to be used device_model = ''qemu-dm'' +# xenpaging, number of pages, or -1 for entire guest memory range +xenpaging = 42 + #----------------------------------------------------------------------------- # boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) # default: hard disk, cd-rom, floppy --- xen-unstable.hg-4.1.22571.orig/tools/python/README.XendConfig +++ xen-unstable.hg-4.1.22571/tools/python/README.XendConfig @@ -120,6 +120,7 @@ otherConfig image.vncdisplay image.vncunused image.hvm.device_model + image.hvm.xenpaging image.hvm.display image.hvm.xauthority image.hvm.vncconsole --- xen-unstable.hg-4.1.22571.orig/tools/python/README.sxpcfg +++ xen-unstable.hg-4.1.22571/tools/python/README.sxpcfg @@ -51,6 +51,7 @@ image - vncunused (HVM) - device_model + - xenpaging - display - xauthority - vncconsole --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/XendConfig.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/XendConfig.py @@ -147,6 +147,7 @@ XENAPI_PLATFORM_CFG_TYPES = { ''apic'': int, ''boot'': str, ''device_model'': str, + ''xenpaging'': int, ''loader'': str, ''display'' : str, ''fda'': str, @@ -508,6 +509,8 @@ class XendConfig(dict): self[''platform''][''nomigrate''] = 0 if self.is_hvm(): + if ''xenpaging'' not in self[''platform'']: + self[''platform''][''xenpaging''] = None if ''timer_mode'' not in self[''platform'']: self[''platform''][''timer_mode''] = 1 if ''viridian'' not in self[''platform'']: --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/XendDomainInfo.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/XendDomainInfo.py @@ -2390,6 +2390,7 @@ class XendDomainInfo: if self.image: self.image.createDeviceModel() + self.image.createXenPaging() #if have pass-through devs, need the virtual pci slots info from qemu self.pci_device_configure_boot() @@ -2402,6 +2403,10 @@ class XendDomainInfo: self.image.destroyDeviceModel() except Exception, e: log.exception("Device model destroy failed %s" % str(e)) + try: + self.image.destroyXenPaging() + except Exception, e: + log.exception("stopping xenpaging failed %s" % str(e)) else: log.debug("No device model") --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/image.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/image.py @@ -122,12 +122,16 @@ class ImageHandler: self.vm.permissionsVm("image/cmdline", { ''dom'': self.vm.getDomid(), ''read'': True } ) self.device_model = vmConfig[''platform''].get(''device_model'') + self.xenpaging = vmConfig[''platform''].get(''xenpaging'') + if self.xenpaging == 0: + self.xenpaging = None self.display = vmConfig[''platform''].get(''display'') self.xauthority = vmConfig[''platform''].get(''xauthority'') self.vncconsole = int(vmConfig[''platform''].get(''vncconsole'', 0)) self.dmargs = self.parseDeviceModelArgs(vmConfig) self.pid = None + self.xenpaging_pid = None rtc_timeoffset = int(vmConfig[''platform''].get(''rtc_timeoffset'', 0)) if int(vmConfig[''platform''].get(''localtime'', 0)): if time.localtime(time.time())[8]: @@ -392,6 +396,89 @@ class ImageHandler: sentinel_fifos_inuse[sentinel_path_fifo] = 1 self.sentinel_path_fifo = sentinel_path_fifo + def createXenPaging(self): + if self.xenpaging is None: + return + if self.xenpaging_pid: + return + xenpaging_bin = auxbin.pathTo("xenpaging") + args = [xenpaging_bin] + args = args + ([ "%d" % self.vm.getDomid()]) + args = args + ([ "%s" % self.xenpaging]) + env = dict(os.environ) + self.xenpaging_logfile = "/var/log/xen/xenpaging-%s.log" % str(self.vm.info[''name_label'']) + logfile_mode = os.O_WRONLY|os.O_CREAT|os.O_APPEND|os.O_TRUNC + null = os.open("/dev/null", os.O_RDONLY) + try: + os.unlink(self.xenpaging_logfile) + except: + pass + logfd = os.open(self.xenpaging_logfile, logfile_mode, 0644) + sys.stderr.flush() + contract = osdep.prefork("%s:%d" % (self.vm.getName(), self.vm.getDomid())) + xenpaging_pid = os.fork() + if xenpaging_pid == 0: #child + try: + xenpaging_dir = "/var/lib/xen/xenpaging" + osdep.postfork(contract) + os.dup2(null, 0) + os.dup2(logfd, 1) + os.dup2(logfd, 2) + try: + os.chdir(xenpaging_dir) + except: + log.warn("chdir %s failed" % xenpaging_dir) + try: + log.info("starting %s" % args) + os.execve(xenpaging_bin, args, env) + except Exception, e: + print >>sys.stderr, ( + ''failed to execute xenpaging: %s: %s'' % + xenpaging_bin, utils.exception_string(e)) + os._exit(126) + except Exception, e: + log.warn("staring xenpaging in %s failed" % xenpaging_dir) + os._exit(127) + else: + osdep.postfork(contract, abandon=True) + self.xenpaging_pid = xenpaging_pid + os.close(null) + os.close(logfd) + + def destroyXenPaging(self): + if self.xenpaging is None: + return + log.debug("stopping xenpaging") + if self.xenpaging_pid: + try: + os.kill(self.xenpaging_pid, signal.SIGHUP) + except OSError, exn: + log.exception(exn) + for i in xrange(100): + try: + (p, rv) = os.waitpid(self.xenpaging_pid, os.WNOHANG) + if p == self.xenpaging_pid: + break + except OSError: + # This is expected if Xend has been restarted within + # the life of this domain. In this case, we can kill + # the process, but we can''t wait for it because it''s + # not our child. We continue this loop, and after it is + # terminated make really sure the process is going away + # (SIGKILL). + pass + time.sleep(0.1) + else: + log.warning("xenpaging %d took more than 10s " + "to terminate: sending SIGKILL" % self.xenpaging_pid) + try: + os.kill(self.xenpaging_pid, signal.SIGKILL) + os.waitpid(self.xenpaging_pid, 0) + except OSError: + # This happens if the process doesn''t exist. + pass + self.xenpaging_pid = None + def createDeviceModel(self, restore = False): if self.device_model is None: return --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xm/create.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xm/create.py @@ -491,6 +491,10 @@ gopts.var(''nfs_root'', val="PATH", fn=set_value, default=None, use="Set the path of the root NFS directory.") +gopts.var(''xenpaging'', val=''NUM'', + fn=set_int, default=None, + use="Number of pages to swap.") + gopts.var(''device_model'', val=''FILE'', fn=set_value, default=None, use="Path to device model program.") @@ -1076,6 +1080,7 @@ def configure_hvm(config_image, vals): args = [ ''acpi'', ''apic'', ''boot'', ''cpuid'', ''cpuid_check'', + ''xenpaging'', ''device_model'', ''display'', ''fda'', ''fdb'', ''gfx_passthru'', ''guest_os_type'', --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xm/xenapi_create.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xm/xenapi_create.py @@ -1085,6 +1085,7 @@ class sxp2xml: ''acpi'', ''apic'', ''boot'', + ''xenpaging'', ''device_model'', ''loader'', ''fda'', _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-10 16:43 UTC
[Xen-devel] [PATCH 12/12] xenpaging: document missing live migration
live migration does not work yet Signed-off-by: Olaf Hering <olaf@aepfle.de> --- docs/misc/xenpaging.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- xen-unstable.hg-4.1.22571.orig/docs/misc/xenpaging.txt +++ xen-unstable.hg-4.1.22571/docs/misc/xenpaging.txt @@ -42,7 +42,7 @@ changes. Todo: - implement stopping of xenpaging -- implement/test live migration +- implement live migration # vim: tw=72 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2011-Jan-11 10:37 UTC
Re: [Xen-devel] [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
Could we do this in free_heap_pages() instead? That definitely catches everything that gets placed in Xen''s free pool. -- Keir On 10/01/2011 16:43, "Olaf Hering" <olaf@aepfle.de> wrote:> The machine_to_phys_mapping[] array needs updating during page > deallocation. If that page is allocated again, a call to > get_gpfn_from_mfn() will still return an old gfn from another guest. > This will cause trouble because this gfn number has no or different > meaning in the context of the current guest. > > This happens when the entire guest ram is paged-out before > xen_vga_populate_vram() runs. Then XENMEM_populate_physmap is called > with gfn 0xff000. A new page is allocated with alloc_domheap_pages. > This new page does not have a gfn yet. However, in > guest_physmap_add_entry() the passed mfn maps still to an old gfn > (perhaps from another old guest). This old gfn is in paged-out state in > this guests context and has no mfn anymore. As a result, the ASSERT() > triggers because p2m_is_ram() is true for p2m_ram_paging* types. > If the machine_to_phys_mapping[] array is updated properly, both loops > in guest_physmap_add_entry() turn into no-ops for the new page and the > mfn/gfn mapping will be done at the end of the function. > > If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn, > get_gpfn_from_mfn() will return an appearently valid gfn. As a result, > guest_physmap_remove_page() is called. The ASSERT in p2m_remove_page > triggers because the passed mfn does not match the old mfn for the > passed gfn. > > > Signed-off-by: Olaf Hering <olaf@aepfle.de> > > --- > xen/common/page_alloc.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > --- xen-unstable.hg-4.1.22571.orig/xen/common/page_alloc.c > +++ xen-unstable.hg-4.1.22571/xen/common/page_alloc.c > @@ -1200,9 +1200,15 @@ void free_domheap_pages(struct page_info > { > int i, drop_dom_ref; > struct domain *d = page_get_owner(pg); > + unsigned long mfn; > > ASSERT(!in_irq()); > > + /* this page is not a gfn anymore */ > + mfn = page_to_mfn(pg); > + for ( i = 0; i < (1 << order); i++ ) > + set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY); > + > if ( unlikely(is_xen_heap_page(pg)) ) > { > /* NB. May recursively lock from relinquish_memory(). */ > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-11 11:00 UTC
Re: [Xen-devel] [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
On Tue, Jan 11, Keir Fraser wrote:> Could we do this in free_heap_pages() instead? That definitely catches > everything that gets placed in Xen''s free pool.Yes, this is a compile-tested patch. The machine_to_phys_mapping[] array needs updating during page deallocation. If that page is allocated again, a call to get_gpfn_from_mfn() will still return an old gfn from another guest. This will cause trouble because this gfn number has no or different meaning in the context of the current guest. This happens when the entire guest ram is paged-out before xen_vga_populate_vram() runs. Then XENMEM_populate_physmap is called with gfn 0xff000. A new page is allocated with alloc_domheap_pages. This new page does not have a gfn yet. However, in guest_physmap_add_entry() the passed mfn maps still to an old gfn (perhaps from another old guest). This old gfn is in paged-out state in this guests context and has no mfn anymore. As a result, the ASSERT() triggers because p2m_is_ram() is true for p2m_ram_paging* types. If the machine_to_phys_mapping[] array is updated properly, both loops in guest_physmap_add_entry() turn into no-ops for the new page and the mfn/gfn mapping will be done at the end of the function. If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn, get_gpfn_from_mfn() will return an appearently valid gfn. As a result, guest_physmap_remove_page() is called. The ASSERT in p2m_remove_page triggers because the passed mfn does not match the old mfn for the passed gfn. Signed-off-by: Olaf Hering <olaf@aepfle.de> --- v2: move from free_domheap_pages() to free_heap_pages() as suggested by Keir xen/common/page_alloc.c | 6 ++++++ 1 file changed, 6 insertions(+) --- xen-unstable.hg-4.1.22697.orig/xen/common/page_alloc.c +++ xen-unstable.hg-4.1.22697/xen/common/page_alloc.c @@ -527,6 +527,7 @@ static int reserve_offlined_page(struct static void free_heap_pages( struct page_info *pg, unsigned int order) { + unsigned long mfn; unsigned long mask; unsigned int i, node = phys_to_nid(page_to_maddr(pg)), tainted = 0; unsigned int zone = page_to_zone(pg); @@ -536,6 +537,11 @@ static void free_heap_pages( spin_lock(&heap_lock); + /* this page is not a gfn anymore */ + mfn = page_to_mfn(pg); + for ( i = 0; i < (1 << order); i++ ) + set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY); + for ( i = 0; i < (1 << order); i++ ) { /* _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2011-Jan-11 11:29 UTC
Re: [Xen-devel] [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
On 11/01/2011 11:00, "Olaf Hering" <olaf@aepfle.de> wrote:> On Tue, Jan 11, Keir Fraser wrote: > >> Could we do this in free_heap_pages() instead? That definitely catches >> everything that gets placed in Xen''s free pool. > > Yes, this is a compile-tested patch.Thanks. I fixed a subtle bug (rather disgustingly, set_gpfn_from_mfn() depends on page_get_owner(mfn_to_page(mfn))), and checked it in as c/s 22706. -- Keir> > The machine_to_phys_mapping[] array needs updating during page > deallocation. If that page is allocated again, a call to > get_gpfn_from_mfn() will still return an old gfn from another guest. > This will cause trouble because this gfn number has no or different > meaning in the context of the current guest. > > This happens when the entire guest ram is paged-out before > xen_vga_populate_vram() runs. Then XENMEM_populate_physmap is called > with gfn 0xff000. A new page is allocated with alloc_domheap_pages. > This new page does not have a gfn yet. However, in > guest_physmap_add_entry() the passed mfn maps still to an old gfn > (perhaps from another old guest). This old gfn is in paged-out state in > this guests context and has no mfn anymore. As a result, the ASSERT() > triggers because p2m_is_ram() is true for p2m_ram_paging* types. > If the machine_to_phys_mapping[] array is updated properly, both loops > in guest_physmap_add_entry() turn into no-ops for the new page and the > mfn/gfn mapping will be done at the end of the function. > > If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn, > get_gpfn_from_mfn() will return an appearently valid gfn. As a result, > guest_physmap_remove_page() is called. The ASSERT in p2m_remove_page > triggers because the passed mfn does not match the old mfn for the > passed gfn. > > > Signed-off-by: Olaf Hering <olaf@aepfle.de> > > --- > v2: > move from free_domheap_pages() to free_heap_pages() as suggested by Keir > > xen/common/page_alloc.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > --- xen-unstable.hg-4.1.22697.orig/xen/common/page_alloc.c > +++ xen-unstable.hg-4.1.22697/xen/common/page_alloc.c > @@ -527,6 +527,7 @@ static int reserve_offlined_page(struct > static void free_heap_pages( > struct page_info *pg, unsigned int order) > { > + unsigned long mfn; > unsigned long mask; > unsigned int i, node = phys_to_nid(page_to_maddr(pg)), tainted = 0; > unsigned int zone = page_to_zone(pg); > @@ -536,6 +537,11 @@ static void free_heap_pages( > > spin_lock(&heap_lock); > > + /* this page is not a gfn anymore */ > + mfn = page_to_mfn(pg); > + for ( i = 0; i < (1 << order); i++ ) > + set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY); > + > for ( i = 0; i < (1 << order); i++ ) > { > /*_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2011-Jan-11 17:20 UTC
Re: [Xen-devel] [PATCH 00/12] xenpaging changes for xen-unstable
Olaf Hering writes ("[Xen-devel] [PATCH 00/12] xenpaging changes for xen-unstable"):> Here are some changes for xenpaging in xen-unstable.Thanks.> New to this series since my last post are patch 1 to 5. > They are likely non-controversial and could be applied.Yes, I intend to apply 1-5 to xen-unstable.hg now unless someone shouts to tell me not to.> Patches 6 and 7 are required to maintain the machine_to_phys_mapping[] > array properly. Unless there are objections to the deallocation part, > they could be applied. > > Patch 8 could be applied as well.Does 8 depend on 6 and 7 ?> As it stands right now, a guest will hang hard with xenpaging once the > balloon driver is loaded in the guest. Its not clear what the issue is, > no memory_op hypercall has been issued yet. xm vcpu-list indicates the > guest makes no progress. I will debug this further.Thanks. Bear in mind that we are in at the end of the release cycle now and the tree is becoming more and more frozen. Since xenpaging doesn''t work properly without your patches they''re bugfixes but we do want to get all of them in sooner rather than later. It''s possible that we''ll have to release without all the changes you might want to make :-/. Thanks, Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2011-Jan-11 18:36 UTC
Re: [Xen-devel] [PATCH 05/12] xenpaging: make three functions static
Olaf Hering writes ("[Xen-devel] [PATCH 05/12] xenpaging: make three functions static"):> xenpaging_init(), xenpaging_teardown() and xenpaging_evict_page() are > only used in file scope, so they can be marked static.I see Keir has applied 1-6. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Olaf Hering
2011-Jan-14 16:53 UTC
Re: [Xen-devel] [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page
On Mon, Jan 10, Olaf Hering wrote:> Simply drop paged-pages in guest_remove_page(), and notify xenpaging to > drop its reference to the gfn. If the ring is full, the page will > remain in paged-out state in xenpaging. This is not an issue, it just > means this gfn will not be nominated again.> send one-way notification to pager to release pageHere I need some help to make that a true one-way event. The currently applied version of the patch just fills up the ring, with the result that the guest can not proceed because there is no way to tell the pager about required page-in requests. How can the request which was just consumed with get_response() be freed from the ring buffer? I tried a modified version of mem_event_pause_vcpu() which does not call mem_event_pause_vcpu(), but that does not change anything. It seems the stuck guest is a result of incorrect mem_event_ring handling. Olaf> +void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn) > +{ > + struct vcpu *v = current; > + mem_event_request_t req; > + struct domain *d = p2m->domain; > + > + /* Check that there''s space on the ring for this request */ > + if ( mem_event_check_ring(d) == 0) > + { > + /* Send release notification to pager */ > + memset(&req, 0, sizeof(req)); > + req.flags |= MEM_EVENT_FLAG_DROP_PAGE; > + req.gfn = gfn; > + req.vcpu_id = v->vcpu_id; > + > + mem_event_put_request(d, &req); > + } > +} > +_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel