|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 4/4] vm_event: Add support for multi-page ring buffer
On Thu, Sep 13, 2018 at 9:02 AM Petre Pircalabu
<ppircalabu@xxxxxxxxxxxxxxx> wrote:
>
> In high throughput introspection scenarios where lots of monitor
> vm_events are generated, the ring buffer can fill up before the monitor
> application gets a chance to handle all the requests thus blocking
> other vcpus which will have to wait for a slot to become available.
>
> This patch adds support for extending the ring buffer by allocating a
> number of pages from domheap and mapping them to the monitor
> application's domain using the foreignmemory_map_resource interface.
> Unlike the current implementation, the ring buffer pages are not part of
> the introspected DomU, so they will not be reclaimed when the monitor is
> disabled.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx>
Thanks for this addition, it has been on the TODO for a long while
now. Could you also please push the patches as a git branch somewhere?
> ---
> tools/libxc/include/xenctrl.h | 2 +
> tools/libxc/xc_monitor.c | 7 +
> tools/libxc/xc_private.h | 3 +
> tools/libxc/xc_vm_event.c | 49 +++++++
> tools/tests/xen-access/xen-access.c | 33 +++--
> xen/arch/x86/domain_page.c | 3 +-
> xen/arch/x86/mm.c | 14 ++
> xen/common/vm_event.c | 258
> +++++++++++++++++++++++++++---------
> xen/include/public/domctl.h | 1 +
> xen/include/public/memory.h | 1 +
> xen/include/xen/sched.h | 5 +-
> xen/include/xen/vm_event.h | 4 +
> 12 files changed, 305 insertions(+), 75 deletions(-)
>
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index bb75bcc..4f91ee9 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -2005,6 +2005,8 @@ int xc_get_mem_access(xc_interface *xch, uint32_t
> domain_id,
> * Caller has to unmap this page when done.
> */
> void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t
> *port);
> +void *xc_monitor_enable_ex(xc_interface *xch, uint32_t domain_id,
> + int order, uint32_t *port);
I don't think there is value in keeping both version of the API
around. As libxc is not considered to be a stable API extending the
existing API would be the route I would prefer. Also, perhaps instead
of "order" name the input variable "page_count" to make it more clear
what it's about.
> int xc_monitor_disable(xc_interface *xch, uint32_t domain_id);
> int xc_monitor_resume(xc_interface *xch, uint32_t domain_id);
> /*
> diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
> index 15e6a0e..5188835 100644
> --- a/tools/libxc/xc_monitor.c
> +++ b/tools/libxc/xc_monitor.c
> @@ -28,6 +28,13 @@ void *xc_monitor_enable(xc_interface *xch, uint32_t
> domain_id, uint32_t *port)
> port);
> }
>
> +void *xc_monitor_enable_ex(xc_interface *xch, uint32_t domain_id, int order,
> + uint32_t *port)
> +{
> + return xc_vm_event_enable_ex(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR,
> + order, port);
> +}
> +
> int xc_monitor_disable(xc_interface *xch, uint32_t domain_id)
> {
> return xc_vm_event_control(xch, domain_id,
> diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
> index be22986..03d9460 100644
> --- a/tools/libxc/xc_private.h
> +++ b/tools/libxc/xc_private.h
> @@ -436,6 +436,9 @@ int xc_vm_event_control(xc_interface *xch, uint32_t
> domain_id, unsigned int op,
> void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
> uint32_t *port);
>
> +void *xc_vm_event_enable_ex(xc_interface *xch, uint32_t domain_id, int type,
> + int order, uint32_t *port);
> +
> int do_dm_op(xc_interface *xch, uint32_t domid, unsigned int nr_bufs, ...);
>
> #endif /* __XC_PRIVATE_H__ */
> diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
> index de37ca5..216bbe2 100644
> --- a/tools/libxc/xc_vm_event.c
> +++ b/tools/libxc/xc_vm_event.c
> @@ -21,6 +21,7 @@
> */
>
> #include "xc_private.h"
> +#include "xenforeignmemory.h"
>
> int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int
> op,
> unsigned int mode, uint32_t *port)
> @@ -184,6 +185,54 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t
> domain_id, int type,
> return ring_page;
> }
>
> +void *xc_vm_event_enable_ex(xc_interface *xch, uint32_t domain_id, int type,
> + int order, uint32_t *port)
> +{
> + xenforeignmemory_resource_handle *fres = NULL;
> + int saved_errno;
> + void *ring_buffer = NULL;
> +
> + if ( !port )
> + {
> + errno = EINVAL;
> + return NULL;
> + }
> +
> + /* Pause the domain for ring page setup */
> + if ( xc_domain_pause(xch, domain_id) )
> + {
> + PERROR("Unable to pause domain\n");
> + return NULL;
> + }
> +
> + fres = xenforeignmemory_map_resource(xch->fmem, domain_id,
> + XENMEM_resource_vm_event, type, 0,
> + order, &ring_buffer,
> + PROT_READ | PROT_WRITE, 0);
> + if ( !fres )
> + {
> + PERROR("Unable to map vm_event ring pages resource\n");
> + goto out;
> + }
> +
> + if ( xc_vm_event_control(xch, domain_id, XEN_VM_EVENT_GET_PORT, type,
> port) )
> + PERROR("Unable to get vm_event channel port\n");
> +
> +out:
> + saved_errno = errno;
> + if ( xc_domain_unpause(xch, domain_id) != 0 )
> + {
> + if (fres)
> + saved_errno = errno;
> + PERROR("Unable to unpause domain");
> + }
> +
> + free(fres);
> + errno = saved_errno;
> + return ring_buffer;
> +}
> +
> +
> /*
> * Local variables:
> * mode: C
> diff --git a/tools/tests/xen-access/xen-access.c
> b/tools/tests/xen-access/xen-access.c
> index 6aaee16..f4c4eda 100644
> --- a/tools/tests/xen-access/xen-access.c
> +++ b/tools/tests/xen-access/xen-access.c
> @@ -68,7 +68,8 @@ typedef struct vm_event {
> int port;
> vm_event_back_ring_t back_ring;
> uint32_t evtchn_port;
> - void *ring_page;
> + void *ring_buffer;
> + unsigned int ring_page_count;
> } vm_event_t;
>
> typedef struct xenaccess {
> @@ -136,8 +137,9 @@ int xenaccess_teardown(xc_interface *xch, xenaccess_t
> *xenaccess)
> return 0;
>
> /* Tear down domain xenaccess in Xen */
> - if ( xenaccess->vm_event.ring_page )
> - munmap(xenaccess->vm_event.ring_page, XC_PAGE_SIZE);
> + if ( xenaccess->vm_event.ring_buffer )
> + munmap(xenaccess->vm_event.ring_buffer,
> + xenaccess->vm_event.ring_page_count * XC_PAGE_SIZE );
>
> if ( mem_access_enable )
> {
> @@ -210,12 +212,25 @@ xenaccess_t *xenaccess_init(xc_interface **xch_r,
> domid_t domain_id)
> /* Set domain id */
> xenaccess->vm_event.domain_id = domain_id;
>
> - /* Enable mem_access */
> - xenaccess->vm_event.ring_page =
> + /* Ring buffer page count */
> + xenaccess->vm_event.ring_page_count = 2;
> +
> + xenaccess->vm_event.ring_buffer = xc_monitor_enable_ex(
> + xenaccess->xc_handle,
> + xenaccess->vm_event.domain_id,
> + xenaccess->vm_event.ring_page_count,
> + &xenaccess->vm_event.evtchn_port);
> +
> + if (xenaccess->vm_event.ring_buffer == NULL && errno == EOPNOTSUPP)
How would this situation ever arise? If there is a chance that you
can't setup multi-page rings, perhaps adding a hypercall that would
tell the user how many pages are max available for the ring is the
better route. This just seems like guessing right now.
> + {
> + xenaccess->vm_event.ring_page_count = 1;
> + xenaccess->vm_event.ring_buffer =
> xc_monitor_enable(xenaccess->xc_handle,
> xenaccess->vm_event.domain_id,
> &xenaccess->vm_event.evtchn_port);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |