Mem event interface improvements
PATCH 1/1 Mem event interface improvements
In this patch series we add a series of improevements to the memory event interface. Namely:
- Allow batched consumption of multiple outstanding responses
- Signal Xen to consume responses solely with an event channel kick
- Extra flag to tag events generated byforeign-domains
- Allow placing dummy domains in the ring, to keep it in sync if a state transition does not require an explicit response.
All these changes are orthogonal to the outstanding proposals for enhancing ring management.
xen/arch/x86/mm/mem_event.c | 6 +++ xen/include/public/mem_event.h | 1 + xen/arch/ia64/vmx/vmx_init.c | 2 +- xen/arch/x86/hvm/hvm.c | 7 ++- xen/arch/x86/mm/mem_event.c | 3 +- xen/common/event_channel.c | 75 +++++++++++++++++++++++++++++++--------- xen/include/xen/event.h | 5 ++- xen/include/xen/sched.h | 2 +- xen/arch/x86/mm/mem_event.c | 26 ++++++++++--- xen/arch/x86/mm/mem_event.c | 10 ++++- xen/arch/x86/mm/mem_sharing.c | 13 +++--- xen/arch/x86/mm/p2m.c | 52 ++++++++++++++------------- xen/include/asm-x86/mem_event.h | 2 +- xen/arch/x86/mm/mem_sharing.c | 2 + xen/arch/x86/mm/p2m.c | 4 ++ xen/include/public/mem_event.h | 7 +++ 16 files changed, 154 insertions(+), 63 deletions(-)
PATCH 1/1 Flag events caused by foreign domains
xen/arch/x86/mm/mem_event.c | 6 ++++++ xen/include/public/mem_event.h | 1 + 2 files changed, 7 insertions(+), 0 deletions(-)
Add a new flag for mem events, as consumers might need to discriminate foreign domain-caused from guest-caused events. The vcpu field of an event is bogus from a consumer p.o.v. for foreign domain-caused events.
Also assert that we shouldn't be pausing foreign vcpus.
xen/arch/x86/mm/mem_event.c +6 -0
@@ -143,6 +143,12 @@ void mem_event_put_request(struct domain front_ring = &med->front_ring; req_prod = front_ring->req_prod_pvt; +if ( current->domain != d ) + { + req->flags |=MEM_EVENT_FLAG_FOREIGN ; +ASSERT ( !(req->flags &MEM_EVENT_FLAG_VCPU_PAUSED ) ); + } +/* Copy request */ memcpy (RING_GET_REQUEST (front_ring, req_prod), req,sizeof (*req)); req_prod++;
xen/include/public/mem_event.h +1 -0
@@ -39,6 +39,7 @@#define MEM_EVENT_FLAG_VCPU_PAUSED (1 << 0)#define MEM_EVENT_FLAG_DROP_PAGE (1 << 1)#define MEM_EVENT_FLAG_EVICT_FAIL (1 << 2) +#define MEM_EVENT_FLAG_FOREIGN (1 << 3)/* Reasons for the memory event request */ #define MEM_EVENT_REASON_UNKNOWN 0/* typical reason */
PATCH 1/1 Create a generic callback mechanism for Xen-bound event channels
In reply to Andres Lagar-Cavillaxen/arch/ia64/vmx/vmx_init.c | 2 +- xen/arch/x86/hvm/hvm.c | 7 ++- xen/arch/x86/mm/mem_event.c | 3 +- xen/common/event_channel.c | 75 ++++++++++++++++++++++++++++++++++--------- xen/include/xen/event.h | 5 ++- xen/include/xen/sched.h | 2 +- 6 files changed, 70 insertions(+), 24 deletions(-)
For event channels for which Xen is the consumer, there currently is a single action. With this patch, we allow event channel creators to specify a generic callback (or no callback). Because the expectation is that there will be few callbacks, they are stored in a small table.
xen/arch/ia64/vmx/vmx_init.c +1 -1
@@ -377,7 +377,7 @@ vmx_vcpu_initialise(struct vcpu *v) {struct vmx_ioreq_page *iorp = &v->domain->arch.hvm_domain.ioreq; -int rc =alloc_unbound_xen_event_channel (v,0 ); +int rc =alloc_unbound_xen_event_channel (v,0 ,NULL );if (rc <0 )return rc; v->arch.arch_vmx.xen_port = rc;
xen/arch/x86/hvm/hvm.c +4 -3
@@ -979,7 +979,7 @@ int hvm_vcpu_initialise(struct vcpu *v) goto fail3;/* Create ioreq event channel. */ - rc =alloc_unbound_xen_event_channel (v,0 ); + rc =alloc_unbound_xen_event_channel (v,0 ,NULL );if ( rc <0 ) goto fail4;
@@ -989,7 +989,7 @@ int hvm_vcpu_initialise(struct vcpu *v)if ( v->vcpu_id ==0 ) {/* Create bufioreq event channel. */ - rc =alloc_unbound_xen_event_channel (v,0 ); + rc =alloc_unbound_xen_event_channel (v,0 ,NULL );if ( rc <0 ) goto fail2; v->domain->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN ] = rc;
@@ -3561,7 +3561,8 @@ long do_hvm_op(unsigned long op, XEN_GUE for_each_vcpu ( d, v ) {int old_port, new_port; - new_port =alloc_unbound_xen_event_channel (v, a.value); + new_port =alloc_unbound_xen_event_channel ( + v, a.value,NULL );if ( new_port <0 ) { rc = new_port;
xen/arch/x86/mm/mem_event.c +2 -1
@@ -93,7 +93,8 @@ static int mem_event_enable(struct domai/* Allocate event channel */ rc =alloc_unbound_xen_event_channel (d->vcpu[0 ], - current->domain->domain_id); + current->domain->domain_id, +NULL );if ( rc <0 ) goto err;
xen/common/event_channel.c +58 -17
141 lines not on this page · raw message
xen/include/xen/event.h +4 -1
@@ -51,8 +51,11 @@ int evtchn_unmask(unsigned int port);void evtchn_move_pirqs (struct vcpu *v);/* Allocate/free a Xen-attached event channel port. */ +typedef void (*xen_event_channel_notification_t )( +struct vcpu *v,unsigned int port);int alloc_unbound_xen_event_channel ( -struct vcpu *local_vcpu,domid_t remote_domid); +struct vcpu *local_vcpu,domid_t remote_domid, +xen_event_channel_notification_t notification_fn);void free_xen_event_channel (struct vcpu *local_vcpu,int port);
xen/include/xen/sched.h +1 -1
@@ -47,7 +47,7 @@ struct evtchn#define ECS_VIRQ 5/* Channel is bound to a virtual IRQ line. */ #define ECS_IPI 6/* Channel is bound to a virtual IPI line. */ u8 state;/* ECS_* */ -u8 consumer_is_xen;/* Consumed by Xen or by guest? */ +u8 xen_consumer;/* Consumer in Xen, if any? (0 = send to guest) */ u16 notify_vcpu_id;/* VCPU for local delivery notification */ union { struct {
PATCH 1/1 Allow memevent responses to be signaled via the event channel
In reply to Andres Lagar-Cavillaxen/arch/x86/mm/mem_event.c | 26 ++++++++++++++++++++------ 1 files changed, 20 insertions(+), 6 deletions(-)
Don't require a separate domctl to notify the memevent interface that an event has occured. This domctl can be taxing, particularly when you are scaling events and paging to many domains across a single system. Instead, we use the existing event channel to signal when we place something in the ring (as per normal ring operation).
xen/arch/x86/mm/mem_event.c +20 -6
@@ -37,9 +37,11 @@#define mem_event_ring_lock (_med) spin_lock(&(_med)->ring_lock)#define mem_event_ring_unlock (_med) spin_unlock(&(_med)->ring_lock) -static int mem_event_enable (struct domain *d, -xen_domctl_mem_event_op_t *mec, -struct mem_event_domain *med) +static int mem_event_enable ( +struct domain *d, +xen_domctl_mem_event_op_t *mec, +struct mem_event_domain *med, +xen_event_channel_notification_t notification_fn) {int rc;struct domain *dom_mem_event = current->domain;
@@ -94,7 +96,7 @@ static int mem_event_enable(struct domai/* Allocate event channel */ rc =alloc_unbound_xen_event_channel (d->vcpu[0 ], current->domain->domain_id, -NULL ); + notification_fn);if ( rc <0 ) goto err;
@@ -233,6 +235,18 @@ int mem_event_check_ring(struct domain *return ring_full; } +/* Registered with Xen-bound event channel for incoming notifications. */ +static void mem_paging_notification (struct vcpu *v,unsigned int port) +{ +p2m_mem_paging_resume (v->domain); +} + +/* Registered with Xen-bound event channel for incoming notifications. */ +static void mem_access_notification (struct vcpu *v,unsigned int port) +{ +p2m_mem_access_resume (v->domain); +} +int mem_event_domctl (struct domain *d,xen_domctl_mem_event_op_t *mec,XEN_GUEST_HANDLE (void ) u_domctl) {
@@ -294,7 +308,7 @@ int mem_event_domctl(struct domain *d, xif ( p2m->pod.entry_count )break ; - rc =mem_event_enable (d, mec, med); + rc =mem_event_enable (d, mec, med, mem_paging_notification); }break ;
@@ -333,7 +347,7 @@ int mem_event_domctl(struct domain *d, xif ( boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL )break ; - rc =mem_event_enable (d, mec, med); + rc =mem_event_enable (d, mec, med, mem_access_notification); }break ;
PATCH 1/1 Consume multiple mem event responses off the ring
In reply to Andres Lagar-Cavillaxen/arch/x86/mm/mem_event.c | 10 +++++++- xen/arch/x86/mm/mem_sharing.c | 13 +++++---- xen/arch/x86/mm/p2m.c | 52 +++++++++++++++++++++------------------- xen/include/asm-x86/mem_event.h | 2 +- 4 files changed, 44 insertions(+), 33 deletions(-)
xen/arch/x86/mm/mem_event.c +9 -1
@@ -166,7 +166,7 @@ void mem_event_put_request(struct domainnotify_via_xen_event_channel (d, med->xen_port); } -void mem_event_get_response (struct mem_event_domain *med,mem_event_response_t *rsp) +int mem_event_get_response (struct mem_event_domain *med,mem_event_response_t *rsp) {mem_event_front_ring_t *front_ring;RING_IDX rsp_cons;
@@ -176,6 +176,12 @@ void mem_event_get_response(struct mem_e front_ring = &med->front_ring; rsp_cons = front_ring->rsp_cons; +if ( !RING_HAS_UNCONSUMED_RESPONSES (front_ring) ) + { +mem_event_ring_unlock (med); +return 0 ; + } +/* Copy response */ memcpy (rsp,RING_GET_RESPONSE (front_ring, rsp_cons),sizeof (*rsp)); rsp_cons++;
@@ -185,6 +191,8 @@ void mem_event_get_response(struct mem_e front_ring->sring->rsp_event = rsp_cons +1 ;mem_event_ring_unlock (med); + +return 1 ; }void mem_event_unpause_vcpus (struct domain *d)
xen/arch/x86/mm/mem_sharing.c +7 -6
@@ -300,12 +300,13 @@ int mem_sharing_sharing_resume(struct do {mem_event_response_t rsp; -/* Get request off the ring */ -mem_event_get_response (&d->mem_event->share, &rsp); - -/* Unpause domain/vcpu */ -if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED ) -vcpu_unpause (d->vcpu[rsp.vcpu_id]); +/* Get all requests off the ring */ +while (mem_event_get_response (&d->mem_event->share, &rsp) ) + { +/* Unpause domain/vcpu */ +if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED ) +vcpu_unpause (d->vcpu[rsp.vcpu_id]); + }return 0 ; }
xen/arch/x86/mm/p2m.c +27 -25
69 lines not on this page · raw message
xen/include/asm-x86/mem_event.h +1 -1
@@ -29,7 +29,7 @@ void mem_event_mark_and_pause(struct vcpint 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); +int mem_event_get_response (struct mem_event_domain *med,mem_event_response_t *rsp);void mem_event_unpause_vcpus (struct domain *d); int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
PATCH 1/1 Ignore memory events with an obviously invalid gfn
In reply to Andres Lagar-Cavillaxen/arch/x86/mm/mem_sharing.c | 2 ++ xen/arch/x86/mm/p2m.c | 4 ++++ xen/include/public/mem_event.h | 7 +++++++ 3 files changed, 13 insertions(+), 0 deletions(-)
Ring semantics require that for every request, a response be put. This allows consumer to place a dummy response if need be.
xen/arch/x86/mm/mem_sharing.c +2 -0
@@ -303,6 +303,8 @@ int mem_sharing_sharing_resume(struct do/* Get all requests off the ring */ while (mem_event_get_response (&d->mem_event->share, &rsp) ) { +if (DUMMY_MEM_EVENT_RSP (&rsp) ) +continue ;/* Unpause domain/vcpu */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )vcpu_unpause (d->vcpu[rsp.vcpu_id]);
xen/arch/x86/mm/p2m.c +4 -0
@@ -1069,6 +1069,8 @@ void p2m_mem_paging_resume(struct domain/* Pull all responses off the ring */ while (mem_event_get_response (&d->mem_event->paging, &rsp) ) { +if (DUMMY_MEM_EVENT_RSP (&rsp) ) +continue ;/* Fix p2m entry if the page was not dropped */ if ( !(rsp.flags &MEM_EVENT_FLAG_DROP_PAGE ) ) {
@@ -1177,6 +1179,8 @@ void p2m_mem_access_resume(struct domain/* Pull all responses off the ring */ while (mem_event_get_response (&d->mem_event->access, &rsp) ) { +if (DUMMY_MEM_EVENT_RSP (&rsp) ) +continue ;/* Unpause domain */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )vcpu_unpause (d->vcpu[rsp.vcpu_id]);
xen/include/public/mem_event.h +7 -0
@@ -76,6 +76,13 @@ typedef struct mem_event_st {DEFINE_RING_TYPES (mem_event, mem_event_request_t, mem_event_response_t); +#define INVALID_RSP_GFN -1UL + +#define DUMMY_MEM_EVENT_RSP (_r) ((_r)->gfn == INVALID_RSP_GFN) +#define MAKE_MEM_EVENT_RSP_DUMMY (_r) ((_r)->gfn = INVALID_RSP_GFN) +#define DECLARE_DUMMY_MEM_EVENT_RSP (_name) \ + mem_event_response_t _name = { .gfn = INVALID_RSP_GFN } +#endif /*
Re: [PATCH 5 of 5] Ignore memory events with an obviously invalid gfn
Quoted 13 lines · Andres Lagar-Cavilla
xen/arch/x86/mm/mem_sharing.c | 2 ++ xen/arch/x86/mm/p2m.c | 4 ++++ xen/include/public/mem_event.h | 7 +++++++ 3 files changed, 13 insertions(+), 0 deletions(-)Ring semantics require that for every request, a response be put. This allows consumer to place a dummy response if need be.
diff -r
c71f4c5b42f0-r790cd814bee8xen/include/public/mem_event.h
xen/include/public/mem_event.h typedef struct mem_event_st { · line 80
Quoted 5 lines
xen/include/public/mem_event.h +2
-0@@ -76,6 +76,13 @@ typedef struct mem_event_st {DEFINE_RING_TYPES (mem_event, mem_event_request_t, mem_event_response_t); +#define INVALID_RSP_GFN -1UL +
On a 32-bit system this doesn't do what you want.
Actually, can you use a flag for this, please? Wedging it into the gfn field seems a bit of a hack, and we have plenty of flag bits left.
Tim.
Quoted 13 lines
xen/include/public/mem_event.h +5
-0+#define DUMMY_MEM_EVENT_RSP (_r) ((_r)->gfn == INVALID_RSP_GFN) +#define MAKE_MEM_EVENT_RSP_DUMMY (_r) ((_r)->gfn = INVALID_RSP_GFN) +#define DECLARE_DUMMY_MEM_EVENT_RSP (_name) \ + mem_event_response_t _name = { .gfn = INVALID_RSP_GFN } +#endif /* _______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 5 of 5] Ignore memory events with an obviously invalid gfn
Quoted 23 lines
Quoted 13 lines · Andres Lagar-Cavilla
xen/arch/x86/mm/mem_sharing.c | 2 ++ xen/arch/x86/mm/p2m.c | 4 ++++ xen/include/public/mem_event.h | 7 +++++++ 3 files changed, 13 insertions(+), 0 deletions(-)Ring semantics require that for every request, a response be put. This allows consumer to place a dummy response if need be.
diff -r
c71f4c5b42f0-r790cd814bee8xen/include/public/mem_event.hxen/include/public/mem_event.h typedef struct mem_event_st { · line 81
Quoted 6 lines
xen/include/public/mem_event.h +2
-0@@ -76,6 +76,13 @@ typedef struct mem_event_st {DEFINE_RING_TYPES (mem_event, mem_event_request_t, mem_event_response_t); +#define INVALID_RSP_GFN -1UL +On a 32-bit system this doesn't do what you want.
Quoted 4 lines
Actually, can you use a flag for this, please? Wedging it into the gfn field seems a bit of a hack, and we have plenty of flag bits left.
Tim.
Good point, here it is:
# HG changeset patch
# Parent c71f4c5b42f0c7cc04e4ae758c8ab775305f2c6a Ignore memory events with an obviously invalid gfn.
Ring semantics require that for every request, a response be put. This allows consumer to place a dummy response if need be.
xen/arch/x86/mm/mem_sharing.c +2 -0
@@ -303,6 +303,8 @@ int mem_sharing_sharing_resume(struct do/* Get all requests off the ring */ while (mem_event_get_response (&d->mem_event->share, &rsp) ) { +if (DUMMY_MEM_EVENT_RSP (&rsp) ) +continue ;/* Unpause domain/vcpu */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )vcpu_unpause (d->vcpu[rsp.vcpu_id]);
xen/arch/x86/mm/p2m.c +4 -0
@@ -1069,6 +1069,8 @@ void p2m_mem_paging_resume(struct domain/* Pull all responses off the ring */ while (mem_event_get_response (&d->mem_event->paging, &rsp) ) { +if (DUMMY_MEM_EVENT_RSP (&rsp) ) +continue ;/* Fix p2m entry if the page was not dropped */ if ( !(rsp.flags &MEM_EVENT_FLAG_DROP_PAGE ) ) {
@@ -1177,6 +1179,8 @@ void p2m_mem_access_resume(struct domain/* Pull all responses off the ring */ while (mem_event_get_response (&d->mem_event->access, &rsp) ) { +if (DUMMY_MEM_EVENT_RSP (&rsp) ) +continue ;/* Unpause domain */ if ( rsp.flags &MEM_EVENT_FLAG_VCPU_PAUSED )vcpu_unpause (d->vcpu[rsp.vcpu_id]);
xen/include/public/mem_event.h +8 -0
@@ -40,6 +40,7 @@#define MEM_EVENT_FLAG_DROP_PAGE (1 << 1)#define MEM_EVENT_FLAG_EVICT_FAIL (1 << 2)#define MEM_EVENT_FLAG_FOREIGN (1 << 3) +#define MEM_EVENT_FLAG_DUMMY (1 << 4)/* Reasons for the memory event request */ #define MEM_EVENT_REASON_UNKNOWN 0/* typical reason */
@@ -76,6 +77,13 @@ typedef struct mem_event_st {DEFINE_RING_TYPES (mem_event, mem_event_request_t, mem_event_response_t); +#define DUMMY_MEM_EVENT_RSP (_r) \ + ((_r)->flags & MEM_EVENT_FLAG_DUMMY) +#define MAKE_MEM_EVENT_RSP_DUMMY (_r) \ + ((_r)->flags |= MEM_EVENT_FLAG_DUMMY) +#define DECLARE_DUMMY_MEM_EVENT_RSP (_name) \ + mem_event_response_t _name = { .flags = MEM_EVENT_FLAG_DUMMY } +#endif /*
Quoted 7 lines · Andres Lagar-Cavilla
In this patch series we add a series of improevements to the memory event interface. Namely:
- Allow batched consumption of multiple outstanding responses
- Signal Xen to consume responses solely with an event channel kick
- Extra flag to tag events generated byforeign-domains
- Allow placing dummy domains in the ring, to keep it in sync if a state transition does not require an explicit response.
Assuming that these patches have been tested, I'm ok with them.
Olaf
Tim Deegan
AppliedQuoted 7 lines · Andres Lagar-Cavilla
In this patch series we add a series of improevements to the memory event interface. Namely:
- Allow batched consumption of multiple outstanding responses
- Signal Xen to consume responses solely with an event channel kick
- Extra flag to tag events generated byforeign-domains
- Allow placing dummy domains in the ring, to keep it in sync if a state transition does not require an explicit response.
Applied, thanks. I stripped out the 'MEM_EVENT_RSP' macros from patch 5, as they didn't seem useful now that it's just a flag, so you might have to fix up your client code to match.
Cheers,
Tim.
Quoted 9 lines
Quoted 7 lines · Andres Lagar-Cavilla
In this patch series we add a series of improevements to the memory event interface. Namely:
- Allow batched consumption of multiple outstanding responses
- Signal Xen to consume responses solely with an event channel kick
- Extra flag to tag events generated byforeign-domains
- Allow placing dummy domains in the ring, to keep it in sync if a state transition does not require an explicit response.
Quoted 7 lines
Applied, thanks. I stripped out the '
MEM_EVENT_RSP' macros from patch 5, as they didn't seem useful now that it's just a flag, so you might have to fix up your client code to match.Cheers,
Tim.
Thanks! no biggie about macros
Andres