xenpaging fixes for xen-unstable
PATCH 1/1 xenpaging fixes for xen-unstable
The following changes for xenpaging add checking for the p2mt in the page-in path to make the functions more robust, add some documentation to each p2m_mem_paging function, and disable paging in a PoD guest.
Please review and apply.
Olaf
tools/xenpaging/xenpaging.c | 3 + xen/arch/x86/mm/mem_event.c | 6 ++ xen/arch/x86/mm/p2m.c | 111 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 4 deletions(-)
PATCH 1/1 xenpaging: check p2mt in p2m_mem_paging functions
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1319034159 -7200
# Node ID f835012a0c062e70495aa341d41e3970a121bf6a # Parent 6880bfc48504db31e2680de01bfadf4db3b0b7a0
xenpaging: check p2mt in p2m_mem_paging functions
Add checks to forward the p2m_ram_paging* state properly during page-in.
Resume can be called several times if several vcpus called populate for the gfn. Finish resume only once.
v2:
- remove debug output for non-p2m_ram_rw case
xen/arch/x86/mm/p2m.c +14 -4
@@ -851,16 +851,22 @@ int p2m_mem_paging_prep(struct domain *dp2m_access_t a;mfn_t mfn;struct p2m_domain *p2m =p2m_get_hostp2m (d); -int ret = -ENOMEM ; +int ret;p2m_lock (p2m); mfn = p2m->get_entry (p2m, gfn, &p2mt, &a, p2m_query,NULL ); + ret = -ENOENT ; +/* Allow only missing pages */ +if ( p2mt != p2m_ram_paging_in_start ) + goto out; +/* Allocate a page if the gfn does not have one yet */ if ( !mfn_valid (mfn) ) {/* Get a free page */ + ret = -ENOMEM ; page =alloc_domheap_page (p2m->domain,0 );if (unlikely (page ==NULL ) ) goto out;
@@ -896,9 +902,13 @@ void p2m_mem_paging_resume(struct domain {p2m_lock (p2m); mfn = p2m->get_entry (p2m, rsp.gfn, &p2mt, &a, p2m_query,NULL ); -set_p2m_entry (p2m, rsp.gfn, mfn,0 , p2m_ram_rw, a); -set_gpfn_from_mfn (mfn_x (mfn), rsp.gfn); -audit_p2m (p2m,1 ); +/* Allow only pages which were prepared properly, or pages which were nominated but not evicted */ +if (mfn_valid (mfn) && ( p2mt == p2m_ram_paging_in || p2mt == p2m_ram_paging_in_start ) ) + { +set_p2m_entry (p2m, rsp.gfn, mfn,0 , p2m_ram_rw, a); +set_gpfn_from_mfn (mfn_x (mfn), rsp.gfn); +audit_p2m (p2m,1 ); + }p2m_unlock (p2m); }
PATCH 1/1 xenpaging: document p2m_mem_paging functions
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1319034159 -7200
# Node ID cc6184fcd784f94165417073935c5fd0c4b4a76e # Parent f835012a0c062e70495aa341d41e3970a121bf6a
xenpaging: document p2m_mem_paging functions
Add some documentation for each of the p2m_mem_paging functions to describe what they ought to do.
xen/arch/x86/mm/p2m.c +93 -0
@@ -668,6 +668,24 @@ set_shared_p2m_entry(struct domain *d, u }#ifdef __x86_64__ +/** +* p2m_mem_paging_nominate - Mark a guest page as to-be-paged-out +* @d: guest domain +* @gfn: guest page to nominate +* +* Returns 0 for success or negative errno values if gfn is not pageable. +* +* p2m_mem_paging_nominate() is called by the pager and checks if a guest page +* can be paged out. If the following conditions are met the p2mt will be +* changed: +* - the gfn is backed by a mfn +* - the p2mt of the gfn is pageable +* - the mfn is not used for IO +* - the mfn has exactly one user and has no special meaning +* +* Once the p2mt is changed the page is readonly for the guest. On success the +* pager can write the page contents to disk and later evict the page. +*/ int p2m_mem_paging_nominate (struct domain *d,unsigned long gfn) {struct page_info *page;
@@ -714,6 +732,25 @@ int p2m_mem_paging_nominate(struct domaireturn ret; } +/** +* p2m_mem_paging_evict - Mark a guest page as paged-out +* @d: guest domain +* @gfn: guest page to evict +* +* Returns 0 for success or negative errno values if eviction is not possible. +* +* p2m_mem_paging_evict() is called by the pager and will free a guest page and +* release it back to Xen. If the following conditions are met the page can be +* freed: +* - the gfn is backed by a mfn +* - the gfn was nominated +* - the mfn has still exactly one user and has no special meaning +* +* After successful nomination some other process could have mapped the page. In +* this case eviction can not be done. If the gfn was populated before the pager +* could evict it, eviction can not be done either. In this case the gfn is +* still backed by a mfn. +*/ int p2m_mem_paging_evict (struct domain *d,unsigned long gfn) {struct page_info *page;
@@ -773,6 +810,15 @@ int p2m_mem_paging_evict(struct domain *return ret; } +/** +* p2m_mem_paging_drop_page - Tell pager to drop its reference to a paged page +* @d: guest domain +* @gfn: guest page to drop +* +* p2m_mem_paging_drop_page() will notify the pager that a paged-out gfn was +* released by the guest. The pager is supposed to drop its reference of the +* gfn. +*/ void p2m_mem_paging_drop_page (struct domain *d,unsigned long gfn) {struct vcpu *v = current;
@@ -791,6 +837,27 @@ void p2m_mem_paging_drop_page(struct dom } } +/** +* p2m_mem_paging_populate - Tell pager to populete a paged page +* @d: guest domain +* @gfn: guest page in paging state +* +* p2m_mem_paging_populate() will notify the pager that a page in any of the +* paging states needs to be written back into the guest. +* This function needs to be called whenever gfn_to_mfn() returns any of the p2m +* paging types because the gfn may not be backed by a mfn. +* +* The gfn can be in any of the paging states, but the pager needs only be +* notified when the gfn is in the paging-out path (paging_out or paged). This +* function may be called more than once from several vcpus. If the vcpu belongs +* to the guest, the vcpu must be stopped and the pager notified that the vcpu +* was stopped. The pager needs to handle several requests for the same gfn. +* +* If the gfn is not in the paging-out path and the vcpu does not belong to the +* guest, nothing needs to be done and the function assumes that a request was +* already sent to the pager. In this case the caller has to try again until the +* gfn is fully paged in again. +*/ void p2m_mem_paging_populate (struct domain *d,unsigned long gfn) {struct vcpu *v = current;
@@ -844,6 +911,17 @@ void p2m_mem_paging_populate(struct domamem_event_put_request (d, &d->mem_paging, &req); } +/** +* p2m_mem_paging_prep - Allocate a new page for the guest +* @d: guest domain +* @gfn: guest page in paging state +* +* p2m_mem_paging_prep() will allocate a new page for the guest if the gfn is +* not backed by a mfn. It is called by the pager. +* It is required that the gfn was already populated. The gfn may already have a +* mfn if populate was called for gfn which was nominated but not evicted. In +* this case only the p2mt needs to be forwarded. +*/ int p2m_mem_paging_prep (struct domain *d,unsigned long gfn) {struct page_info *page;
@@ -886,6 +964,21 @@ int p2m_mem_paging_prep(struct domain *dreturn ret; } +/** +* p2m_mem_paging_resume - Resume guest gfn and vcpus +* @d: guest domain +* @gfn: guest page in paging state +* +* p2m_mem_paging_resume() will forward the p2mt of a gfn to ram_rw and all +* waiting vcpus will be unpaused again. It is called by the pager. +* +* The gfn was previously either evicted and populated, or nominated and +* populated. If the page was evicted the p2mt will be p2m_ram_paging_in. If +* the page was just nominated the p2mt will be p2m_ram_paging_in_start because +* the pager did not call p2m_mem_paging_prep(). +* +* If the gfn was dropped the vcpu needs to be unpaused. +*/ void p2m_mem_paging_resume (struct domain *d) {struct p2m_domain *p2m =p2m_get_hostp2m (d);
PATCH 1/1 xenpaging: disallow paging in a PoD guest
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1319034160 -7200
# Node ID d56219addb9e921a02bce5fa8a97c43eba9bc914 # Parent cc6184fcd784f94165417073935c5fd0c4b4a76e
xenpaging: disallow paging in a PoD guest
Disallow xenpaging in a PoD guest until coexistance between the two features is properly implemented.
tools/xenpaging/xenpaging.c +3 -0
@@ -246,6 +246,9 @@ static xenpaging_t *xenpaging_init(domidcase ENODEV :ERROR ("EPT not supported for this guest" );break ; +case EXDEV : +ERROR ("xenpaging not supported in a PoD guest" ); +break ;default :ERROR ("Error initialising shared page: %s" ,strerror (errno));break ;
xen/arch/x86/mm/mem_event.c +6 -0
@@ -253,6 +253,7 @@ int mem_event_domctl(struct domain *d, xcase XEN_DOMCTL_MEM_EVENT_OP_PAGING : {struct mem_event_domain *med = &d->mem_paging; +struct p2m_domain *p2m =p2m_get_hostp2m (d); rc = -ENODEV ;/* Only HAP is supported */ if ( !hap_enabled (d) )
@@ -262,6 +263,11 @@ int mem_event_domctl(struct domain *d, xif ( boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL )break ; + rc = -EXDEV ; +/* Disallow paging in a PoD guest */ +if ( p2m->pod.entry_count ) +break ; +switch ( mec->op ) {case XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE :
Tim Deegan
AppliedQuoted 6 lines · Olaf Hering
The following changes for xenpaging add checking for the p2mt in the page-in path to make the functions more robust, add some documentation to each
p2m_mem_pagingfunction, and disable paging in a PoD guest.Please review and apply.
Applied, thanks. Double thanks for adding documentation!
Tim.