RFC: wait queue usage
PATCH 1/1 RFC: wait queue usage
The following series is my current state of an attempt to use wait queues for xenpaging and mem_event handling. I post it here for review and comments.
Olaf
xen/arch/x86/hvm/hvm.c | 6 +- xen/arch/x86/mm/mem_event.c | 82 +++++++++++++++++++++++++++++++++------- xen/arch/x86/mm/mem_sharing.c | 31 +++++---------- xen/arch/x86/mm/p2m-ept.c | 46 +++++++++++++++++++--- xen/arch/x86/mm/p2m.c | 56 ++++++++++++++------------- xen/common/domain.c | 5 ++ xen/include/asm-x86/mem_event.h | 4 - xen/include/asm-x86/p2m.h | 1 xen/include/xen/sched.h | 32 +++++++++++---- 9 files changed, 183 insertions(+), 80 deletions(-)
PATCH 1/1 mem_event: move mem_event_domain out of struct domain
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1321996135 -3600
# Node ID d347a8a36d2e7951f98a3d22866dce004484d95f # Parent d3859e348951cde6b211c5afb610ac1f12a909ecmem_event: move mem_event_domain out of struct domain
An upcoming change increases the size of mem_event_domain. The result is a build failure because struct domain gets larger than a page. Allocate the room for the three mem_event_domain members at runtime.
xen/arch/x86/hvm/hvm.c +2 -2
@@ -4098,7 +4098,7 @@ static int hvm_memory_event_traps(long pif ( (p & HVMPME_onchangeonly) && (value == old) )return 1 ; - rc =mem_event_check_ring (d, &d->mem_access); + rc =mem_event_check_ring (d, &d->mem_event->mem_access);if ( rc )return rc;
@@ -4121,7 +4121,7 @@ static int hvm_memory_event_traps(long p req.gla_valid =1 ; } -mem_event_put_request (d, &d->mem_access, &req); +mem_event_put_request (d, &d->mem_event->mem_access, &req);return 1 ; }
xen/arch/x86/mm/mem_event.c +3 -3
@@ -265,7 +265,7 @@ int mem_event_domctl(struct domain *d, x {case XEN_DOMCTL_MEM_EVENT_OP_PAGING : { -struct mem_event_domain *med = &d->mem_paging; +struct mem_event_domain *med = &d->mem_event->mem_paging; rc = -EINVAL ; switch( mec->op )
@@ -310,7 +310,7 @@ int mem_event_domctl(struct domain *d, xcase XEN_DOMCTL_MEM_EVENT_OP_ACCESS : { -struct mem_event_domain *med = &d->mem_access; +struct mem_event_domain *med = &d->mem_event->mem_access; rc = -EINVAL ; switch( mec->op )
@@ -333,7 +333,7 @@ int mem_event_domctl(struct domain *d, xcase XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE : {if ( med->ring_page ) - rc =mem_event_disable (&d->mem_access); + rc =mem_event_disable (med); }break ;
xen/arch/x86/mm/mem_sharing.c +3 -3
@@ -281,12 +281,12 @@ static struct page_info* mem_sharing_allvcpu_pause_nosync (v); req.flags |=MEM_EVENT_FLAG_VCPU_PAUSED ; -if (mem_event_check_ring (d, &d->mem_share))return page; +if (mem_event_check_ring (d, &d->mem_event->mem_share))return page; req.gfn = gfn; req.p2mt = p2m_ram_shared; req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_share, &req); +mem_event_put_request (d, &d->mem_event->mem_share, &req);return page; }
@@ -301,7 +301,7 @@ int mem_sharing_sharing_resume(struct domem_event_response_t rsp;/* Get request off the ring */ -mem_event_get_response (&d->mem_share, &rsp); +mem_event_get_response (&d->mem_event->mem_share, &rsp);/* Unpause domain/vcpu */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )
xen/arch/x86/mm/p2m.c +9 -9
@@ -885,7 +885,7 @@ void p2m_mem_paging_drop_page(struct dommem_event_request_t req;/* Check that there's space on the ring for this request */ -if (mem_event_check_ring (d, &d->mem_paging) ==0 ) +if (mem_event_check_ring (d, &d->mem_event->mem_paging) ==0 ) {/* Send release notification to pager */ memset (&req,0 ,sizeof (req));
@@ -893,7 +893,7 @@ void p2m_mem_paging_drop_page(struct dom req.gfn = gfn; req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_paging, &req); +mem_event_put_request (d, &d->mem_event->mem_paging, &req); } }
@@ -928,7 +928,7 @@ void p2m_mem_paging_populate(struct domastruct p2m_domain *p2m =p2m_get_hostp2m (d);/* Check that there's space on the ring for this request */ -if (mem_event_check_ring (d, &d->mem_paging) ) +if (mem_event_check_ring (d, &d->mem_event->mem_paging) )return ;memset (&req,0 ,sizeof (req));
@@ -959,7 +959,7 @@ void p2m_mem_paging_populate(struct domaelse if ( p2mt != p2m_ram_paging_out && p2mt != p2m_ram_paged ) {/* gfn is already on its way back and vcpu is not paused */ -mem_event_put_req_producers (&d->mem_paging); +mem_event_put_req_producers (&d->mem_event->mem_paging);return ; }
@@ -968,7 +968,7 @@ void p2m_mem_paging_populate(struct doma req.p2mt = p2mt; req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_paging, &req); +mem_event_put_request (d, &d->mem_event->mem_paging, &req); }/**
@@ -1048,7 +1048,7 @@ void p2m_mem_paging_resume(struct domainmfn_t mfn;/* Pull the response off the ring */ -mem_event_get_response (&d->mem_paging, &rsp); +mem_event_get_response (&d->mem_event->mem_paging, &rsp);/* Fix p2m entry if the page was not dropped */ if ( !(rsp.flags &MEM_EVENT_FLAG_DROP_PAGE ) )
@@ -1101,7 +1101,7 @@ void p2m_mem_access_check(unsigned longp2m_unlock (p2m);/* Otherwise, check if there is a memory event listener, and send the message along */ - res =mem_event_check_ring (d, &d->mem_access); + res =mem_event_check_ring (d, &d->mem_event->mem_access);if ( res <0 ) {/* No listener */
@@ -1145,7 +1145,7 @@ void p2m_mem_access_check(unsigned long req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_access, &req); +mem_event_put_request (d, &d->mem_event->mem_access, &req);/* VCPU paused, mem event request sent */ }
@@ -1155,7 +1155,7 @@ void p2m_mem_access_resume(struct p2m_dostruct domain *d = p2m->domain;mem_event_response_t rsp; -mem_event_get_response (&d->mem_access, &rsp); +mem_event_get_response (&d->mem_event->mem_access, &rsp);/* Unpause domain */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )
xen/common/domain.c +5 -0
@@ -304,6 +304,10 @@ struct domain *domain_create( init_status |= INIT_gnttab; poolid =0 ; + + d->mem_event = xzalloc(struct mem_event_per_domain); +if ( !d->mem_event ) + goto fail; }if (arch_domain_create (d, domcr_flags) !=0 )
@@ -335,6 +339,7 @@ struct domain *domain_create( fail: d->is_dying = DOMDYING_dead;atomic_set (&d->refcnt,DOMAIN_DESTROYED ); +xfree (d->mem_event);if ( init_status & INIT_arch )arch_domain_destroy (d);if ( init_status & INIT_gnttab )
xen/include/xen/sched.h +12 -6
@@ -194,6 +194,16 @@ struct mem_event_domainint xen_port; }; +struct mem_event_per_domain +{ +/* Memory sharing support */ +struct mem_event_domain mem_share; +/* Memory paging support */ +struct mem_event_domain mem_paging; +/* Memory access support */ +struct mem_event_domain mem_access; +}; +struct domain {domid_t domain_id;
@@ -318,12 +328,8 @@ struct domain/* Non-migratable and non-restoreable? */ bool_t disable_migrate; -/* Memory sharing support */ -struct mem_event_domain mem_share; -/* Memory paging support */ -struct mem_event_domain mem_paging; -/* Memory access support */ -struct mem_event_domain mem_access; +/* Various mem_events */ +struct mem_event_per_domain *mem_event;/* Currently computed from union of all vcpu cpu-affinity masks. */ nodemask_t node_affinity;
PATCH 1/1 RFC: mem_event: use wait queue when ring is full
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1321996145 -3600
# Node ID de6860cb9205b68d1287482288d1b7b9d0255609 # Parent d347a8a36d2e7951f98a3d22866dce004484d95f
RFC: mem_event: use wait queue when ring is full
CAUTION: while the patch by itself is supposed to be complete, the added usage of waitqueues will lead to sudden host reboots!
This change is based on an idea/patch from Adin Scannell.
If the ring is full, put the current vcpu to sleep if it belongs to the target domain. The wakeup happens in the p2m_*_resume functions. A request from another domain will use the existing ->req_producers functionality because sleeping is not possible if the vcpu does not belong to the target domain.
This change fixes also a bug in p2m_mem_paging_drop_page(). Up to now a full ring will lead to harmless inconsistency in the pager,
v2:
- p2m_mem_paging_populate: move vcpu_pause after put_request, otherwise the vcpu will not wake_up after a wait_event because the pause_count was increased twice. Fixes guest hangs.
- update free space check in _mem_event_put_request()
- simplify mem_event_put_request()
xen/arch/x86/hvm/hvm.c +1 -1
@@ -4099,7 +4099,7 @@ static int hvm_memory_event_traps(long preturn 1 ; rc =mem_event_check_ring (d, &d->mem_event->mem_access); -if ( rc ) +if ( rc <0 )return rc;memset (&req,0 ,sizeof (req));
xen/arch/x86/mm/mem_event.c +65 -11
162 lines not on this page · raw message
xen/arch/x86/mm/mem_sharing.c +10 -17
@@ -253,19 +253,11 @@ static void mem_sharing_audit(void)#endif -static struct page_info *mem_sharing_alloc_page (struct domain *d, -unsigned long gfn) +static void mem_sharing_notify_helper (struct domain *d,unsigned long gfn) { -struct page_info * page;struct vcpu *v = current;mem_event_request_t req; - page =alloc_domheap_page (d,0 ); -if (page !=NULL )return page; - -memset (&req,0 ,sizeof (req)); - req.type =MEM_EVENT_TYPE_SHARED ; -if ( v->domain != d ) {/* XXX This path needs some attention. For now, just fail foreign
@@ -275,20 +267,20 @@ static struct page_info* mem_sharing_allgdprintk (XENLOG_ERR ,"Failed alloc on unshare path for foreign (%d) lookup\n" , d->domain_id); -return page; +return ; } -vcpu_pause_nosync (v); - req.flags |=MEM_EVENT_FLAG_VCPU_PAUSED ; +if (mem_event_check_ring (d, &d->mem_event->mem_share) <0 ) +return ; -if (mem_event_check_ring (d, &d->mem_event->mem_share))return page; - +memset (&req,0 ,sizeof (req)); + req.type =MEM_EVENT_TYPE_SHARED ; + req.flags =MEM_EVENT_FLAG_VCPU_PAUSED ; req.gfn = gfn; req.p2mt = p2m_ram_shared; req.vcpu_id = v->vcpu_id;mem_event_put_request (d, &d->mem_event->mem_share, &req); - -return page; +vcpu_pause_nosync (v); }unsigned int mem_sharing_get_nr_saved_mfns (void )
@@ -653,7 +645,7 @@ gfn_found:if (ret ==0 ) goto private_page_found; old_page = page; - page =mem_sharing_alloc_page (d, gfn); + page =alloc_domheap_page (d,0 );if (!page) {/* We've failed to obtain memory for private page. Need to re-add the
@@ -661,6 +653,7 @@ gfn_found:list_add (&gfn_info->list, &hash_entry->gfns);put_gfn (d, gfn);shr_unlock (); +mem_sharing_notify_helper (d, gfn);return -ENOMEM ; }
xen/arch/x86/mm/p2m.c +20 -19
@@ -884,17 +884,13 @@ void p2m_mem_paging_drop_page(struct domstruct vcpu *v = current;mem_event_request_t req; -/* Check that there's space on the ring for this request */ -if (mem_event_check_ring (d, &d->mem_event->mem_paging) ==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; +/* 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, &d->mem_event->mem_paging, &req); - } +mem_event_put_request (d, &d->mem_event->mem_paging, &req); }/**
@@ -952,7 +948,6 @@ void p2m_mem_paging_populate(struct doma/* Pause domain if request came from guest and gfn has paging type */ if (p2m_is_paging (p2mt) && v->domain == d ) { -vcpu_pause_nosync (v); req.flags |=MEM_EVENT_FLAG_VCPU_PAUSED ; }/* No need to inform pager if the gfn is not in the page-out path */
@@ -969,6 +964,10 @@ void p2m_mem_paging_populate(struct doma req.vcpu_id = v->vcpu_id;mem_event_put_request (d, &d->mem_event->mem_paging, &req); + +/* Pause guest after put_request to allow wake_up after wait_event */ +if ( req.flags &MEM_EVENT_FLAG_VCPU_PAUSED ) +vcpu_pause_nosync (v); }/**
@@ -1071,8 +1070,8 @@ void p2m_mem_paging_resume(struct domainif ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )vcpu_unpause (d->vcpu[rsp.vcpu_id]); -/* Unpause any domains that were paused because the ring was full */ -mem_event_unpause_vcpus (d); +/* Unpause all vcpus that were paused because the ring was full */ +wake_up (&d->mem_event->mem_paging.wq); } void p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long gla,
@@ -1111,7 +1110,7 @@ void p2m_mem_access_check(unsigned long"Memory access permissions failure, no mem_event listener: pausing VCPU %d, dom %d\n" , v->vcpu_id, d->domain_id); -mem_event_mark_and_pause (v); +mem_event_mark_and_pause (v, &d->mem_event->mem_access); }else {
@@ -1131,8 +1130,7 @@ void p2m_mem_access_check(unsigned long req.reason =MEM_EVENT_REASON_VIOLATION ;/* Pause the current VCPU unconditionally */ -vcpu_pause_nosync (v); - req.flags |=MEM_EVENT_FLAG_VCPU_PAUSED ; + req.flags =MEM_EVENT_FLAG_VCPU_PAUSED ;/* Send request to mem event */ req.gfn = gfn;
@@ -1148,6 +1146,7 @@ void p2m_mem_access_check(unsigned longmem_event_put_request (d, &d->mem_event->mem_access, &req);/* VCPU paused, mem event request sent */ +vcpu_pause_nosync (v); }void p2m_mem_access_resume (struct p2m_domain *p2m)
@@ -1161,9 +1160,11 @@ void p2m_mem_access_resume(struct p2m_doif ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )vcpu_unpause (d->vcpu[rsp.vcpu_id]); -/* Unpause any domains that were paused because the ring was full or no listener -* was available */ -mem_event_unpause_vcpus (d); +/* Wakeup all vcpus waiting because the ring was full */ +wake_up (&d->mem_event->mem_access.wq); + +/* Unpause all vcpus that were paused because no listener was available */ +mem_event_unpause_vcpus (d, &d->mem_event->mem_access); }
xen/include/asm-x86/mem_event.h +2 -2
@@ -25,12 +25,12 @@#define __MEM_EVENT_H__/* Pauses VCPU while marking pause flag for mem event */ -void mem_event_mark_and_pause (struct vcpu *v); +void mem_event_mark_and_pause (struct vcpu *v,struct mem_event_domain *med);int mem_event_check_ring (struct domain *d,struct mem_event_domain *med);void mem_event_put_req_producers (struct mem_event_domain *med);void mem_event_put_request (struct domain *d,struct mem_event_domain *med,mem_event_request_t *req);void mem_event_get_response (struct mem_event_domain *med,mem_event_response_t *rsp); -void mem_event_unpause_vcpus (struct domain *d); +void mem_event_unpause_vcpus (struct domain *d,struct mem_event_domain *med);int mem_event_domctl (struct domain *d,xen_domctl_mem_event_op_t *mec,XEN_GUEST_HANDLE (void ) u_domctl);
xen/include/xen/sched.h +11 -3
@@ -14,6 +14,7 @@#include <xen/nodemask.h> #include <xen/radix-tree.h> #include <xen/multicall.h> +#include <xen/wait.h> #include <public/xen.h> #include <public/domctl.h> #include <public/sysctl.h>
@@ -192,6 +193,10 @@ struct mem_event_domainmem_event_front_ring_t front_ring;/* event channel port (vcpu0 only) */ int xen_port; +/* mem_event bit for vcpu->pause_flags */ +int mem_event_bit; +/* list of vcpus waiting for room in the ring */ +struct waitqueue_head wq; };struct mem_event_per_domain
@@ -615,9 +620,12 @@ static inline struct domain *next_domain/* VCPU affinity has changed: migrating to a new CPU. */ #define _VPF_migrating 3#define VPF_migrating (1UL<<_VPF_migrating) -/* VCPU is blocked on memory-event ring. */ -#define _VPF_mem_event 4 -#define VPF_mem_event (1UL<<_VPF_mem_event) +/* VCPU is blocked on mem_paging ring. */ +#define _VPF_me_mem_paging 4 +#define VPF_me_mem_paging (1UL<<_VPF_me_mem_paging) +/* VCPU is blocked on mem_access ring. */ +#define _VPF_me_mem_access 5 +#define VPF_me_mem_access (1UL<<_VPF_me_mem_access)static inline int vcpu_runnable (struct vcpu *v) {
PATCH 1/1 RFC: xenpaging: use waitqueue in ept_get
In reply to Olaf Hering# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1321996199 -3600
# Node ID 9d63ecd3969bb7a2e39841f6c859b4c23f750642 # Parent de6860cb9205b68d1287482288d1b7b9d0255609
RFC: xenpaging: use waitqueue in ept_get
xen/arch/x86/mm/p2m-ept.c +39 -7
@@ -505,7 +505,7 @@ out: }/* Read ept p2m entries */ -static mfn_t ept_get_entry (struct p2m_domain *p2m, +static unsigned long _ept_get_entry (struct p2m_domain *p2m,unsigned long gfn,p2m_type_t *t,p2m_access_t * a,p2m_query_t q,unsigned int *page_order) {
@@ -516,7 +516,7 @@ static mfn_t ept_get_entry(struct p2m_dou32 index;int i;int ret =0 ; -mfn_t mfn =_mfn (INVALID_MFN ); +unsigned long mfn =INVALID_MFN ; *t = p2m_mmio_dm; *a = p2m_access_n;
@@ -582,17 +582,14 @@ static mfn_t ept_get_entry(struct p2m_do *t = ept_entry->sa_p2mt; *a = ept_entry->access; - mfn =_mfn (ept_entry->mfn); + mfn = ept_entry->mfn;if ( i ) {/* * We may meet super pages, and to split into 4k pages * to emulate p2m table */ -unsigned long split_mfn =mfn_x (mfn) + - (gfn_remainder & - ((1 << (i *EPT_TABLE_ORDER )) -1 )); - mfn =_mfn (split_mfn); + mfn += (gfn_remainder & ((1 << (i *EPT_TABLE_ORDER )) -1 )); }if ( page_order )
@@ -604,6 +601,41 @@ out:return mfn; } +static int +ept_get_entry_wait (unsigned long *mfn,int *populated, +struct p2m_domain *p2m,unsigned long gfn, +p2m_type_t *t,p2m_access_t *a,p2m_query_t q, +unsigned int *page_order) +{ +int ret =1 ; + *mfn =_ept_get_entry (p2m, gfn, t, a, q, page_order); + +/* No further action in case of query */ +if ( q == p2m_query ) + goto done; + +/* Populate the page once in case of guest access, then go to sleep */ +if (p2m_is_paging (*t) && current->domain == p2m->domain ) { +if ( *populated ==0 ) { + *populated =1 ; +p2m_mem_paging_populate (p2m->domain, gfn); + } + ret =0 ; + } +done: +return ret; +} +static mfn_t +ept_get_entry (struct p2m_domain *p2m,unsigned long gfn, +p2m_type_t *t,p2m_access_t *a,p2m_query_t q, +unsigned int *page_order) +{ +unsigned long mfn; +int populated =0 ; +wait_event (p2m->wq,ept_get_entry_wait (&mfn, &populated, p2m, gfn, t, a, q, page_order)); +return _mfn (mfn); +} +/* WARNING: Only caller doesn't care about PoD pages. So this function will * always return 0 for PoD pages, not populate them. If that becomes necessary, * pass a p2m_query_t type along to distinguish. */
xen/arch/x86/mm/p2m.c +3 -0
@@ -76,6 +76,7 @@ static void p2m_initialise(struct domainINIT_PAGE_LIST_HEAD (&p2m->pages);INIT_PAGE_LIST_HEAD (&p2m->pod.super);INIT_PAGE_LIST_HEAD (&p2m->pod.single); +init_waitqueue_head (&p2m->wq); p2m->domain = d; p2m->default_access = p2m_access_rwx;
@@ -1072,6 +1073,8 @@ void p2m_mem_paging_resume(struct domain/* Unpause all vcpus that were paused because the ring was full */ wake_up (&d->mem_event->mem_paging.wq); +/* Unpause all vcpus that were paused because the gfn was paged */ +wake_up (&p2m->wq); } void p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long gla,
xen/include/asm-x86/p2m.h +1 -0
@@ -286,6 +286,7 @@ struct p2m_domain {unsigned reclaim_single;/* Last gpfn of a scan */ unsigned max_guest;/* gpfn of max guest demand-populate */ } pod; +struct waitqueue_head wq; };/* get host p2m table */
Re: [PATCH 1 of 3] mem_event: move mem_event_domain out of struct domain
In reply to Olaf HeringQuoted 8 lines
Quoted 1 line
Quoted 1 line · Olaf Hering
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1321996135 -3600
# Node IDd347a8a36d2e7951f98a3d22866dce004484d95f# Parentd3859e348951cde6b211c5afb610ac1f12a909ecmem_event: movemem_event_domainout of struct domain
Quoted 4 lines
An upcoming change increases the size of
mem_event_domain. The result is a build failure because struct domain gets larger than a page. Allocate the room
for the threemem_event_domainmembers at runtime.
This looks like a good general cleanup thing to me. One comment below.
Quoted 192 lines
Signed-off-by Olaf Hering <[email protected]>diff -r
d3859e348951-rd347a8a36d2exen/arch/x86/hvm/hvm.cxen/arch/x86/hvm/hvm.c +2
-2@@ -4098,7 +4098,7 @@ static int hvm_memory_event_traps(long pif ( (p & HVMPME_onchangeonly) && (value == old) )return 1 ; - rc =mem_event_check_ring (d, &d->mem_access); + rc =mem_event_check_ring (d, &d->mem_event->mem_access);if ( rc )return rc;@@ -4121,7 +4121,7 @@ static int hvm_memory_event_traps(long p req.gla_valid =1 ; } -mem_event_put_request (d, &d->mem_access, &req); +mem_event_put_request (d, &d->mem_event->mem_access, &req);return 1 ; }diff -r
d3859e348951-rd347a8a36d2exen/arch/x86/mm/mem_event.cxen/arch/x86/mm/mem_event.c +3
-3@@ -265,7 +265,7 @@ int mem_event_domctl(struct domain *d, x {case XEN_DOMCTL_MEM_EVENT_OP_PAGING : { -struct mem_event_domain *med = &d->mem_paging; +struct mem_event_domain *med = &d->mem_event->mem_paging; rc = -EINVAL ; switch( mec->op )@@ -310,7 +310,7 @@ int mem_event_domctl(struct domain *d, xcase XEN_DOMCTL_MEM_EVENT_OP_ACCESS : { -struct mem_event_domain *med = &d->mem_access; +struct mem_event_domain *med = &d->mem_event->mem_access; rc = -EINVAL ; switch( mec->op )@@ -333,7 +333,7 @@ int mem_event_domctl(struct domain *d, xcase XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE : {if ( med->ring_page ) - rc =mem_event_disable (&d->mem_access); + rc =mem_event_disable (med); }break ;diff -r
d3859e348951-rd347a8a36d2exen/arch/x86/mm/mem_sharing.cxen/arch/x86/mm/mem_sharing.c +3
-3@@ -281,12 +281,12 @@ static struct page_info* mem_sharing_allvcpu_pause_nosync (v); req.flags |=MEM_EVENT_FLAG_VCPU_PAUSED ; -if (mem_event_check_ring (d, &d->mem_share))return page; +if (mem_event_check_ring (d, &d->mem_event->mem_share))return page; req.gfn = gfn; req.p2mt = p2m_ram_shared; req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_share, &req); +mem_event_put_request (d, &d->mem_event->mem_share, &req);return page; }@@ -301,7 +301,7 @@ int mem_sharing_sharing_resume(struct domem_event_response_t rsp;/* Get request off the ring */ -mem_event_get_response (&d->mem_share, &rsp); +mem_event_get_response (&d->mem_event->mem_share, &rsp);/* Unpause domain/vcpu */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )diff -r
d3859e348951-rd347a8a36d2exen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +6
-6@@ -885,7 +885,7 @@ void p2m_mem_paging_drop_page(struct dommem_event_request_t req;/* Check that there's space on the ring for this request */ -if (mem_event_check_ring (d, &d->mem_paging) ==0 ) +if (mem_event_check_ring (d, &d->mem_event->mem_paging) ==0 ) {/* Send release notification to pager */ memset (&req,0 ,sizeof (req));@@ -893,7 +893,7 @@ void p2m_mem_paging_drop_page(struct dom req.gfn = gfn; req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_paging, &req); +mem_event_put_request (d, &d->mem_event->mem_paging, &req); } }@@ -928,7 +928,7 @@ void p2m_mem_paging_populate(struct domastruct p2m_domain *p2m =p2m_get_hostp2m (d);/* Check that there's space on the ring for this request */ -if (mem_event_check_ring (d, &d->mem_paging) ) +if (mem_event_check_ring (d, &d->mem_event->mem_paging) )return ;memset (&req,0 ,sizeof (req));@@ -959,7 +959,7 @@ void p2m_mem_paging_populate(struct domaelse if ( p2mt != p2m_ram_paging_out && p2mt != p2m_ram_paged ) {/* gfn is already on its way back and vcpu is not paused */ -mem_event_put_req_producers (&d->mem_paging); +mem_event_put_req_producers (&d->mem_event->mem_paging);return ; }@@ -968,7 +968,7 @@ void p2m_mem_paging_populate(struct doma req.p2mt = p2mt; req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_paging, &req); +mem_event_put_request (d, &d->mem_event->mem_paging, &req); }/** @@ -1048,7 +1048,7 @@ void p2m_mem_paging_resume(struct domainmfn_t mfn;/* Pull the response off the ring */ -mem_event_get_response (&d->mem_paging, &rsp); +mem_event_get_response (&d->mem_event->mem_paging, &rsp);/* Fix p2m entry if the page was not dropped */ if ( !(rsp.flags &MEM_EVENT_FLAG_DROP_PAGE ) )@@ -1101,7 +1101,7 @@ void p2m_mem_access_check(unsigned longp2m_unlock (p2m);/* Otherwise, check if there is a memory event listener, and send the message along */
xen/arch/x86/mm/p2m.c +3
-3- res =mem_event_check_ring (d, &d->mem_access); + res =mem_event_check_ring (d, &d->mem_event->mem_access);if ( res <0 ) {/* No listener */ @@ -1145,7 +1145,7 @@ void p2m_mem_access_check(unsigned long req.vcpu_id = v->vcpu_id; -mem_event_put_request (d, &d->mem_access, &req); +mem_event_put_request (d, &d->mem_event->mem_access, &req);/* VCPU paused, mem event request sent */ }@@ -1155,7 +1155,7 @@ void p2m_mem_access_resume(struct p2m_dostruct domain *d = p2m->domain;mem_event_response_t rsp; -mem_event_get_response (&d->mem_access, &rsp); +mem_event_get_response (&d->mem_event->mem_access, &rsp);/* Unpause domain */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )diff -r
d3859e348951-rd347a8a36d2exen/common/domain.cxen/common/domain.c +5
-0@@ -304,6 +304,10 @@ struct domain *domain_create( init_status |= INIT_gnttab; poolid =0 ; + + d->mem_event = xzalloc(struct mem_event_per_domain); +if ( !d->mem_event ) + goto fail; }if (arch_domain_create (d, domcr_flags) !=0 )@@ -335,6 +339,7 @@ struct domain *domain_create( fail: d->is_dying = DOMDYING_dead;atomic_set (&d->refcnt,DOMAIN_DESTROYED ); +xfree (d->mem_event);if ( init_status & INIT_arch )arch_domain_destroy (d);if ( init_status & INIT_gnttab )diff -r
d3859e348951-rd347a8a36d2exen/include/xen/sched.hxen/include/xen/sched.h +0
-0@@ -194,6 +194,16 @@ struct mem_event_domainint xen_port;
xen/include/xen/sched.h struct mem_event_domain · line 204
Quoted 10 lines
xen/include/xen/sched.h +8
-0}; +struct mem_event_per_domain +{ +/* Memory sharing support */ +struct mem_event_domain mem_share; +/* Memory paging support */ +struct mem_event_domain mem_paging; +/* Memory access support */ +struct mem_event_domain mem_access;
Could we drop the mem_ prefixes here? Reduces typing as well as line wrapping pressure.
Jan
Quoted 25 lines
xen/include/xen/sched.h +4
-6+}; +struct domain {domid_t domain_id;@@ -318,12 +328,8 @@ struct domain/* Non-migratable and non-restoreable? */ bool_t disable_migrate; -/* Memory sharing support */ -struct mem_event_domain mem_share; -/* Memory paging support */ -struct mem_event_domain mem_paging; -/* Memory access support */ -struct mem_event_domain mem_access; +/* Various mem_events */ +struct mem_event_per_domain *mem_event;/* Currently computed from union of all vcpu cpu-affinity masks. */ nodemask_t node_affinity;_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 2 of 3] RFC: mem_event: use wait queue when ring is full
In reply to Olaf HeringQuoted 12 lines
Quoted 1 line
Quoted 1 line · Olaf Hering
xen/include/xen/sched.h +1
-0@@ -14,6 +14,7 @@#include <xen/nodemask.h> #include <xen/radix-tree.h> #include <xen/multicall.h> +#include <xen/wait.h> #include <public/xen.h> #include <public/domctl.h> #include <public/sysctl.h>
xen/include/xen/sched.h struct mem_event_domain · line 197
Quoted 5 lines
xen/include/xen/sched.h +2
-0@@ -192,6 +193,10 @@ struct mem_event_domainmem_event_front_ring_t front_ring;/* event channel port (vcpu0 only) */ int xen_port; +/* mem_event bit for vcpu->pause_flags */ +int mem_event_bit;
Perhaps pause_bit would be a better name here? Or at least, as for the first patch, the mem_ prefix should go away (or really the mem_event_ one, but that would just leave "bit", which is how I got to the above proposal).
Quoted 8 lines
xen/include/xen/sched.h +2
-0+/* list of vcpus waiting for room in the ring */ +struct waitqueue_head wq; };struct mem_event_per_domain @@ -615,9 +620,12 @@ static inline struct domain *next_domain/* VCPU affinity has changed: migrating to a new CPU. */ #define _VPF_migrating 3
xen/include/xen/sched.h static inline struct domain *next_domain · line 628
Quoted 10 lines
xen/include/xen/sched.h +6
-3#define VPF_migrating (1UL<<_VPF_migrating) -/* VCPU is blocked on memory-event ring. */ -#define _VPF_mem_event 4 -#define VPF_mem_event (1UL<<_VPF_mem_event) +/* VCPU is blocked on mem_paging ring. */ +#define _VPF_me_mem_paging 4 +#define VPF_me_mem_paging (1UL<<_VPF_me_mem_paging) +/* VCPU is blocked on mem_access ring. */ +#define _VPF_me_mem_access 5 +#define VPF_me_mem_access (1UL<<_VPF_me_mem_access)
Same here - the mem_ seems superfluous.
Jan
Quoted 8 lines
xen/include/xen/sched.h +0
-0static inline int vcpu_runnable (struct vcpu *v) {_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 3 of 3] RFC: xenpaging: use waitqueue in ept_get
In reply to Olaf HeringQuoted 14 lines
Quoted 1 line
Quoted 1 line · Olaf Hering
# HG changeset patch
# User Olaf Hering <[email protected]>
# Date 1321996199 -3600
# Node ID9d63ecd3969bb7a2e39841f6c859b4c23f750642# Parentde6860cb9205b68d1287482288d1b7b9d0255609
RFC: xenpaging: use waitqueue inept_getSigned-off-by Olaf Hering <[email protected]>diff -r
de6860cb9205-r9d63ecd3969bxen/arch/x86/mm/p2m-ept.c
xen/arch/x86/mm/p2m-ept.c out: · line 508
Quoted 5 lines
xen/arch/x86/mm/p2m-ept.c +1
-1@@ -505,7 +505,7 @@ out: }/* Read ept p2m entries */ -static mfn_t ept_get_entry(struct p2m_domain *p2m, +static unsigned long _ept_get_entry(struct p2m_domain *p2m,
Looking at the rest of the patch I can't see why the type change here and below is necessary. It is my understanding that the wrapped types exist to reduce the chance of mistakes, so they should be kept whenever possible.
Jan
Quoted 115 lines
xen/arch/x86/mm/p2m-ept.c +38
-6unsigned long gfn, p2m_type_t *t, p2m_access_t* a, p2m_query_t q, unsigned int *page_order) {@@ -516,7 +516,7 @@ static mfn_t ept_get_entry(struct p2m_dou32 index;int i;int ret =0 ; -mfn_t mfn =_mfn (INVALID_MFN ); +unsigned long mfn =INVALID_MFN ; *t = p2m_mmio_dm; *a = p2m_access_n;@@ -582,17 +582,14 @@ static mfn_t ept_get_entry(struct p2m_do *t = ept_entry->sa_p2mt; *a = ept_entry->access; - mfn =_mfn (ept_entry->mfn); + mfn = ept_entry->mfn;if ( i ) {/* * We may meet super pages, and to split into 4k pages * to emulate p2m table */ -unsigned long split_mfn =mfn_x (mfn) + - (gfn_remainder & - ((1 << (i *EPT_TABLE_ORDER )) -1 )); - mfn =_mfn (split_mfn); + mfn += (gfn_remainder & ((1 << (i *EPT_TABLE_ORDER )) -1 )); }if ( page_order )@@ -604,6 +601,41 @@ out:return mfn; } +static int +ept_get_entry_wait (unsigned long *mfn,int *populated, +struct p2m_domain *p2m,unsigned long gfn, +p2m_type_t *t,p2m_access_t *a,p2m_query_t q, +unsigned int *page_order) +{ +int ret =1 ; + *mfn =_ept_get_entry (p2m, gfn, t, a, q, page_order); + +/* No further action in case of query */ +if ( q == p2m_query ) + goto done; + +/* Populate the page once in case of guest access, then go to sleep */ +if (p2m_is_paging (*t) && current->domain == p2m->domain ) { +if ( *populated ==0 ) { + *populated =1 ; +p2m_mem_paging_populate (p2m->domain, gfn); + } + ret =0 ; + } +done: +return ret; +} +static mfn_t +ept_get_entry (struct p2m_domain *p2m,unsigned long gfn, +p2m_type_t *t,p2m_access_t *a,p2m_query_t q, +unsigned int *page_order) +{ +unsigned long mfn; +int populated =0 ; +wait_event (p2m->wq,ept_get_entry_wait (&mfn, &populated, p2m, gfn, t, a, q, page_order)); +return _mfn (mfn); +} +/* WARNING: Only caller doesn't care about PoD pages. So this function will
* always return 0 for PoD pages, not populate them. If that becomes
necessary,
* pass ap2m_query_ttype along to distinguish. */
diff -rde6860cb9205-r9d63ecd3969bxen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +3
-0@@ -76,6 +76,7 @@ static void p2m_initialise(struct domainINIT_PAGE_LIST_HEAD (&p2m->pages);INIT_PAGE_LIST_HEAD (&p2m->pod.super);INIT_PAGE_LIST_HEAD (&p2m->pod.single); +init_waitqueue_head (&p2m->wq); p2m->domain = d; p2m->default_access = p2m_access_rwx;@@ -1072,6 +1073,8 @@ void p2m_mem_paging_resume(struct domain/* Unpause all vcpus that were paused because the ring was full */ wake_up (&d->mem_event->mem_paging.wq); +/* Unpause all vcpus that were paused because the gfn was paged */ +wake_up (&p2m->wq); } void p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsignedlong gla,
diff -rde6860cb9205-r9d63ecd3969bxen/include/asm-x86/p2m.hxen/include/asm-x86/p2m.h +1
-0@@ -286,6 +286,7 @@ struct p2m_domain {unsigned reclaim_single;/* Last gpfn of a scan */ unsigned max_guest;/* gpfn of max guest demand-populate */ } pod; +struct waitqueue_head wq; };/* get host p2m table */
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 2 of 3] RFC: mem_event: use wait queue when ring is full
In reply to Jan BeulichQuoted 14 lines · Jan Beulich
Quoted 14 lines
Quoted 1 line
Quoted 1 line · Olaf Hering
xen/include/xen/sched.h +1
-0@@ -14,6 +14,7 @@#include <xen/nodemask.h> #include <xen/radix-tree.h> #include <xen/multicall.h> +#include <xen/wait.h> #include <public/xen.h> #include <public/domctl.h> #include <public/sysctl.h> @@ -192,6 +193,10 @@ struct mem_event_domainmem_event_front_ring_t front_ring;/* event channel port (vcpu0 only) */
Quoted 8 lines
xen/include/xen/sched.h struct mem_event_domain · line 197
Quoted 3 lines
xen/include/xen/sched.h +2
-0int xen_port; +/* mem_event bit for vcpu->pause_flags */ +int mem_event_bit;Perhaps
pause_bitwould be a better name here? Or at least, as for the first patch, themem_prefix should go away (or really themem_event_one, but that would just leave "bit", which is how I got to the above proposal).
Yes, mem_event_bit is a lazy name here. Doesn't really describe what the bit is actually for. It's obviously mem_event related because of the struct it is a member of.
Quoted 4 lines
Quoted 4 lines
xen/include/xen/sched.h +2
-0+/* list of vcpus waiting for room in the ring */ +struct waitqueue_head wq; };
Quoted 16 lines
Quoted 4 lines
xen/include/xen/sched.h +0
-0struct mem_event_per_domain @@ -615,9 +620,12 @@ static inline struct domain *next_domain/* VCPU affinity has changed: migrating to a new CPU. */ #define _VPF_migrating 3xen/include/xen/sched.h static inline struct domain *next_domain · line 628
Quoted 10 lines
xen/include/xen/sched.h +6
-3#define VPF_migrating (1UL<<_VPF_migrating) -/* VCPU is blocked on memory-event ring. */ -#define _VPF_mem_event 4 -#define VPF_mem_event (1UL<<_VPF_mem_event) +/* VCPU is blocked on mem_paging ring. */ +#define _VPF_me_mem_paging 4 +#define VPF_me_mem_paging (1UL<<_VPF_me_mem_paging) +/* VCPU is blocked on mem_access ring. */ +#define _VPF_me_mem_access 5 +#define VPF_me_mem_access (1UL<<_VPF_me_mem_access)Same here - the
mem_seems superfluous.
Mem_event-related flags in a more general grouping do require a mem_ prefix imo. The names need to stand on their own and still be descriptive.
-- Keir
Quoted 18 lines
Jan
Quoted 8 lines
xen/include/xen/sched.h +0
-0static inline int vcpu_runnable (struct vcpu *v) {_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 2 of 3] RFC: mem_event: use wait queue when ring is full
Quoted 20 lines
Quoted 1 line
Quoted 1 line · Keir Fraser
Quoted 16 lines · Jan Beulich
Quoted 4 lines
Quoted 1 line
Quoted 1 line · Olaf Hering
xen/include/xen/sched.h +0
-0@@ -615,9 +620,12 @@ static inline struct domain *next_domain/* VCPU affinity has changed: migrating to a new CPU. */ #define _VPF_migrating 3xen/include/xen/sched.h static inline struct domain *next_domain · line 628
Quoted 10 lines
xen/include/xen/sched.h +6
-3#define VPF_migrating (1UL<<_VPF_migrating) -/* VCPU is blocked on memory-event ring. */ -#define _VPF_mem_event 4 -#define VPF_mem_event (1UL<<_VPF_mem_event) +/* VCPU is blocked on mem_paging ring. */ +#define _VPF_me_mem_paging 4 +#define VPF_me_mem_paging (1UL<<_VPF_me_mem_paging) +/* VCPU is blocked on mem_access ring. */ +#define _VPF_me_mem_access 5 +#define VPF_me_mem_access (1UL<<_VPF_me_mem_access)Same here - the
mem_seems superfluous.
Quoted 2 lines
Mem_event-related flags in a more general grouping do require a
mem_prefix imo. The names need to stand on their own and still be descriptive.
But me_mem_ is still bogus - I thought the me_ stands for "mem event", and then the subsequent mem_ is unnecessary.
Jan
Re: [PATCH 2 of 3] RFC: mem_event: use wait queue when ring is full
Quoted 9 lines · Jan Beulich
Quoted 9 lines
Quoted 8 lines
xen/include/xen/sched.h static inline struct domain *next_domain · line 628
Quoted 6 lines
+ /* VCPU is blocked on
mem_pagingring. */xen/include/xen/sched.h +5
-0+#define _VPF_me_mem_paging 4 +#define VPF_me_mem_paging (1UL<<_VPF_me_mem_paging) +/* VCPU is blocked on mem_access ring. */ +#define _VPF_me_mem_access 5 +#define VPF_me_mem_access (1UL<<_VPF_me_mem_access)Same here - the
mem_seems superfluous.
Quoted 5 lines
Quoted 2 lines
Mem_event-related flags in a more general grouping do require a
mem_prefix imo. The names need to stand on their own and still be descriptive.But
me_mem_is still bogus - I thought theme_stands for "mem event", and then the subsequentmem_is unnecessary.
I'd get rid of the me_ rather than the mem_. The me_ is too short to be meaningful really.
-- Keir