# HG changeset patch # Parent 5a299906312e606553e6dd2acbe44ab692722a75 xenpaging: improve evict error handling Adjust return codes in Xen and handle errors in evict_victim() properly. p2m_mem_paging_nominate() returns -EAGAIN, p2m_mem_paging_evict() returns -EBUSY. Other errors indicate guest failures, which xenpaging_evict_page() can now catch correctly. Also write() failures are fatal. Without this change, evict_victim() may spin forever if the guest is killed because this function does not get a signal. Signed-off-by: Olaf Hering --- tools/xenpaging/xenpaging.c | 47 ++++++++++++++++++++++++++--------------- xen/arch/x86/mm/p2m.c | 7 +----- xen/include/public/mem_event.h | 2 - 3 files changed, 33 insertions(+), 23 deletions(-) Index: xen-4.1.2-testing/tools/xenpaging/xenpaging.c =================================================================== --- xen-4.1.2-testing.orig/tools/xenpaging/xenpaging.c +++ xen-4.1.2-testing/tools/xenpaging/xenpaging.c @@ -569,29 +569,35 @@ static int xenpaging_evict_page(xenpagin xc_interface *xch = paging->xc_handle; void *page; unsigned long gfn; - int ret; + int ret = -1; DECLARE_DOMCTL; /* Map page to get a handle */ gfn = victim->gfn; - ret = -EFAULT; page = xc_map_foreign_pages(xch, paging->mem_event.domain_id, PROT_READ | PROT_WRITE, &gfn, 1); if ( page == NULL ) { - PERROR("Error mapping page %lx", victim->gfn); + if ( errno == EINVAL ) + ret = 1; + else + PERROR("Error mapping page %lx", victim->gfn); goto out; } /* Nominate the page */ - ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, gfn); - if ( ret != 0 ) + if ( xc_mem_paging_nominate(xch, paging->mem_event.domain_id, gfn) ) + { + if ( errno == EAGAIN ) + ret = 1; + else + PERROR("Error nominating page %lx", victim->gfn); goto out; + } /* Copy page */ - ret = write_page(fd, page, i); - if ( ret != 0 ) + if ( write_page(fd, page, i) ) { PERROR("Error copying page %lx", victim->gfn); goto out; @@ -601,10 +607,10 @@ static int xenpaging_evict_page(xenpagin page = NULL; /* Tell Xen to evict page */ - ret = xc_mem_paging_evict(xch, paging->mem_event.domain_id, - victim->gfn); - if ( ret != 0 ) + if ( xc_mem_paging_evict(xch, paging->mem_event.domain_id, victim->gfn) ) { + if ( errno == EBUSY ) + ret = 1; PERROR("Error evicting page %lx", victim->gfn); goto out; } @@ -616,6 +622,8 @@ static int xenpaging_evict_page(xenpagin /* Record number of evicted pages */ paging->num_paged_out++; + ret = 0; + out: if (page) munmap(page, PAGE_SIZE); @@ -724,7 +732,7 @@ static int evict_victim(xenpaging_t *pag xenpaging_victim_t *victim, int fd, int i) { xc_interface *xch = paging->xc_handle; - int j = 0; + static int num_paged_out; int ret; do @@ -732,9 +740,13 @@ static int evict_victim(xenpaging_t *pag ret = policy_choose_victim(paging, victim); if ( ret != 0 ) { - if ( ret != -ENOSPC ) - ERROR("Error choosing victim"); - goto out; + if ( num_paged_out != paging->num_paged_out ) { + DPRINTF("Flushing qemu cache\n"); + xenpaging_mem_paging_flush_ioemu_cache(paging); + num_paged_out = paging->num_paged_out; + } + ret = -ENOSPC; + goto out; } if ( interrupted ) @@ -742,11 +754,12 @@ static int evict_victim(xenpaging_t *pag ret = -EINTR; goto out; } + ret = xenpaging_evict_page(paging, victim, fd, i); - if ( ret && j++ % 1000 == 0 ) + if ( ret < 0 ) { - if ( xenpaging_mem_paging_flush_ioemu_cache(paging) ) - PERROR("Error flushing ioemu cache"); + ret = -EINTR; + goto out; } } while ( ret ); Index: xen-4.1.2-testing/xen/arch/x86/mm/p2m.c =================================================================== --- xen-4.1.2-testing.orig/xen/arch/x86/mm/p2m.c +++ xen-4.1.2-testing/xen/arch/x86/mm/p2m.c @@ -2863,19 +2863,17 @@ int p2m_mem_paging_nominate(struct p2m_d p2m_type_t p2mt; p2m_access_t a; mfn_t mfn; - int ret; + int ret = -EAGAIN; p2m_lock(p2m); mfn = p2m->get_entry(p2m, gfn, &p2mt, &a, p2m_query); /* 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; @@ -2928,7 +2926,7 @@ int p2m_mem_paging_evict(struct p2m_doma p2m_access_t a; mfn_t mfn; struct domain *d = p2m->domain; - int ret = -EINVAL; + int ret = -EBUSY; p2m_lock(p2m); @@ -2941,7 +2939,6 @@ int p2m_mem_paging_evict(struct p2m_doma if ( p2mt != p2m_ram_paging_out ) goto out; - ret = -EBUSY; /* Get the page so it doesn't get modified under Xen's feet */ page = mfn_to_page(mfn); if ( unlikely(!get_page(page, d)) ) Index: xen-4.1.2-testing/xen/include/public/mem_event.h =================================================================== --- xen-4.1.2-testing.orig/xen/include/public/mem_event.h +++ xen-4.1.2-testing/xen/include/public/mem_event.h @@ -49,7 +49,7 @@ #define MEM_EVENT_REASON_INT3 5 /* int3 was hit: gla/gfn are RIP */ #define MEM_EVENT_REASON_SINGLESTEP 6 /* single step was invoked: gla/gfn are RIP */ -#define MEM_EVENT_PAGING_AGE 2UL /* Number distinguish the mem_paging <-> pager interface */ +#define MEM_EVENT_PAGING_AGE 3UL /* Number distinguish the mem_paging <-> pager interface */ typedef struct mem_event_shared_page { uint32_t port;