Subject: xenpaging: drop paged pages in guest_remove_page Simply drop paged-pages in guest_remove_page(), and notify xenpaging to drop reference to the gfn. (xen-unstable changeset: 22705:c5b42971234a) Signed-off-by: Olaf Hering --- v2: resume dropped page to unpause vcpus tools/xenpaging/xenpaging.c | 17 +++++++--- xen/arch/x86/mm/p2m.c | 65 +++++++++++++++++++++++++++++++---------- xen/common/memory.c | 6 +++ xen/include/asm-x86/p2m.h | 4 ++ xen/include/public/mem_event.h | 1 5 files changed, 73 insertions(+), 20 deletions(-) Index: xen-4.0.2-testing/tools/xenpaging/xenpaging.c =================================================================== --- xen-4.0.2-testing.orig/tools/xenpaging/xenpaging.c +++ xen-4.0.2-testing/tools/xenpaging/xenpaging.c @@ -601,12 +601,19 @@ 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("Dropping page %"PRIx64" p2mt %x\n", req.gfn, req.p2mt); + } + 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 */ Index: xen-4.0.2-testing/xen/arch/x86/mm/p2m.c =================================================================== --- xen-4.0.2-testing.orig/xen/arch/x86/mm/p2m.c +++ xen-4.0.2-testing/xen/arch/x86/mm/p2m.c @@ -2011,12 +2011,15 @@ p2m_remove_page(struct domain *d, unsign 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 = d->arch.p2m->get_entry(d, gfn + i, &t, 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 = d->arch.p2m->get_entry(d, gfn + i, &t, 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(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid); } @@ -2540,6 +2543,35 @@ int p2m_mem_paging_evict(struct domain * return 0; } +void p2m_mem_paging_drop_page(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; + + gfn_to_mfn(d, gfn, &p2mt); + /* Pause domain */ + if ( v->domain->domain_id == d->domain_id ) + { + vcpu_pause_nosync(v); + req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED; + } + + /* Send request to pager */ + req.flags |= MEM_EVENT_FLAG_DROP_PAGE; + req.gfn = gfn; + req.p2mt = p2mt; + req.vcpu_id = v->vcpu_id; + + mem_event_put_request(d, &req); +} + void p2m_mem_paging_populate(struct domain *d, unsigned long gfn) { struct vcpu *v = current; @@ -2604,17 +2636,20 @@ void p2m_mem_paging_resume(struct domain /* Pull the response off the ring */ mem_event_get_response(d, &rsp); - /* Fix p2m entry */ - mfn = gfn_to_mfn(d, rsp.gfn, &p2mt); - if ( mfn_valid(mfn) ) + if ( !( rsp.flags & MEM_EVENT_FLAG_DROP_PAGE ) ) { - p2m_lock(d->arch.p2m); - set_p2m_entry(d, rsp.gfn, mfn, 0, p2m_ram_rw); - set_gpfn_from_mfn(mfn_x(mfn), rsp.gfn); - p2m_unlock(d->arch.p2m); - } else { - gdprintk(XENLOG_ERR, "invalid mfn %lx for gfn %lx p2mt %x flags %lx\n", - mfn_x(mfn), rsp.gfn, p2mt, (unsigned long)rsp.flags); + /* Fix p2m entry */ + mfn = gfn_to_mfn(d, rsp.gfn, &p2mt); + if ( mfn_valid(mfn) ) + { + p2m_lock(d->arch.p2m); + set_p2m_entry(d, rsp.gfn, mfn, 0, p2m_ram_rw); + set_gpfn_from_mfn(mfn_x(mfn), rsp.gfn); + p2m_unlock(d->arch.p2m); + } else { + gdprintk(XENLOG_ERR, "invalid mfn %lx for gfn %lx p2mt %x flags %lx\n", + mfn_x(mfn), rsp.gfn, p2mt, (unsigned long)rsp.flags); + } } /* Unpause domain */ Index: xen-4.0.2-testing/xen/common/memory.c =================================================================== --- xen-4.0.2-testing.orig/xen/common/memory.c +++ xen-4.0.2-testing/xen/common/memory.c @@ -162,6 +162,12 @@ int guest_remove_page(struct domain *d, #ifdef CONFIG_X86 mfn = mfn_x(gfn_to_mfn(d, gmfn, &p2mt)); + if ( unlikely(p2m_is_paging(p2mt)) ) + { + guest_physmap_remove_page(d, gmfn, mfn, 0); + p2m_mem_paging_drop_page(d, gmfn); + return 1; + } #else mfn = gmfn_to_mfn(d, gmfn); #endif Index: xen-4.0.2-testing/xen/include/asm-x86/p2m.h =================================================================== --- xen-4.0.2-testing.orig/xen/include/asm-x86/p2m.h +++ xen-4.0.2-testing/xen/include/asm-x86/p2m.h @@ -441,6 +441,8 @@ int set_shared_p2m_entry(struct domain * 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); +/* Tell xenpaging to drop a paged out frame */ +void p2m_mem_paging_drop_page(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 */ @@ -448,6 +450,8 @@ int p2m_mem_paging_prep(struct domain *d /* Resume normal operation (in case a domain was paused) */ void p2m_mem_paging_resume(struct domain *d); #else +static inline void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn) +{ } static inline void p2m_mem_paging_populate(struct domain *d, unsigned long gfn) { } #endif Index: xen-4.0.2-testing/xen/include/public/mem_event.h =================================================================== --- xen-4.0.2-testing.orig/xen/include/public/mem_event.h +++ xen-4.0.2-testing/xen/include/public/mem_event.h @@ -37,6 +37,7 @@ #define MEM_EVENT_FLAG_VCPU_PAUSED (1 << 0) #define MEM_EVENT_FLAG_DOM_PAUSED (1 << 1) #define MEM_EVENT_FLAG_OUT_OF_MEM (1 << 2) +#define MEM_EVENT_FLAG_DROP_PAGE (1 << 3) typedef struct mem_event_shared_page {