|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
On 30/05/2019 15:18, Petre Pircalabu 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 a different mechanism to handle synchronous
> vm_event requests / responses. As each synchronous request pauses the
> vcpu until the corresponding response is handled, it can be stored in
> a slotted memory buffer (one per vcpu) shared between the hypervisor and
> the controlling domain.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx>
There are a number of concerns here.
First and foremost, why is a new domctl being added? Surely this should
just be a "type of ring access" parameter to event_enable? Everything
else in the vm_event set of APIs should be unchanged as a result of the
interface differences.
Or am I missing something?
> diff --git a/xen/common/vm_event_ng.c b/xen/common/vm_event_ng.c
> new file mode 100644
> index 0000000..17ae33c
> --- /dev/null
> +++ b/xen/common/vm_event_ng.c
> <snip>
>
> +static int vm_event_channels_alloc_buffer(struct vm_event_channels_domain
> *impl)
> +{
> + int i, rc = -ENOMEM;
> +
> + for ( i = 0; i < impl->nr_frames; i++ )
> + {
> + struct page_info *page = alloc_domheap_page(impl->ved.d, 0);
This creates pages which are reference-able (in principle) by the guest,
and are bounded by d->max_pages.
Both of these are properties of the existing interface which we'd prefer
to remove.
> + if ( !page )
> + goto err;
> +
> + if ( !get_page_and_type(page, impl->ved.d, PGT_writable_page) )
> + {
> + rc = -ENODATA;
> + goto err;
> + }
> +
> + impl->mfn[i] = page_to_mfn(page);
> + }
> +
> + impl->slots = (struct vm_event_slot *)vmap(impl->mfn, impl->nr_frames);
You appear to have opencoded vmalloc() here. Is there any reason not to
use that?
> + if ( !impl->slots )
> + goto err;
> +
> + for ( i = 0; i < impl->nr_frames; i++ )
> + clear_page((void*)impl->slots + i * PAGE_SIZE);
> +
> + return 0;
> +
> +err:
> + while ( --i >= 0 )
> + {
> + struct page_info *page = mfn_to_page(impl->mfn[i]);
> +
> + if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
> + put_page(page);
> + put_page_and_type(page);
> + }
> +
> + return rc;
> +}
> +
> +static void vm_event_channels_free_buffer(struct vm_event_channels_domain
> *impl)
> +{
> + int i;
> +
> + ASSERT(impl);
> +
> + if ( !impl->slots )
> + return;
> +
> + vunmap(impl->slots);
> +
> + for ( i = 0; i < impl->nr_frames; i++ )
> + {
> + struct page_info *page = mfn_to_page(impl->mfn[i]);
> +
> + ASSERT(page);
mfn_to_page() is going to explode before this ASSERT() does.
> + if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
> + put_page(page);
> + put_page_and_type(page);
> + }
> +}
> +
> +static int vm_event_channels_create(
> + struct domain *d,
> + struct xen_domctl_vm_event_ng_op *vec,
> + struct vm_event_domain **_ved,
> + int pause_flag,
> + xen_event_channel_notification_t notification_fn)
> +{
> + int rc, i;
> + unsigned int nr_frames = PFN_UP(d->max_vcpus * sizeof(struct
> vm_event_slot));
> + struct vm_event_channels_domain *impl;
> +
> + if ( *_ved )
> + return -EBUSY;
> +
> + impl = _xzalloc(sizeof(struct vm_event_channels_domain) +
> + nr_frames * sizeof(mfn_t),
> + __alignof__(struct vm_event_channels_domain));
> + if ( unlikely(!impl) )
> + return -ENOMEM;
> +
> + spin_lock_init(&impl->ved.lock);
> + spin_lock(&impl->ved.lock);
> +
> + impl->nr_frames = nr_frames;
> + impl->ved.d = d;
> + impl->ved.ops = &vm_event_channels_ops;
> +
> + rc = vm_event_init_domain(d);
> + if ( rc < 0 )
> + goto err;
> +
> + rc = vm_event_channels_alloc_buffer(impl);
> + if ( rc )
> + goto err;
> +
> + for ( i = 0; i < d->max_vcpus; i++ )
> + {
> + rc = alloc_unbound_xen_event_channel(d, i,
> current->domain->domain_id,
> + notification_fn);
> + if ( rc < 0 )
> + goto err;
> +
> + impl->slots[i].port = rc;
> + impl->slots[i].state = STATE_VM_EVENT_SLOT_IDLE;
> + }
> +
> + impl->enabled = false;
> +
> + spin_unlock(&impl->ved.lock);
> + *_ved = &impl->ved;
> + return 0;
> +
> +err:
> + spin_unlock(&impl->ved.lock);
> + XFREE(impl);
You don't free the event channels on error.
Please write make the destructor idempotent and call it from here.
> + return rc;
> +}
> +
> <snip>
> +int vm_event_ng_domctl(struct domain *d, struct xen_domctl_vm_event_ng_op
> *vec,
> + XEN_GUEST_HANDLE_PARAM(void) u_domctl)
> +{
> + int rc;
> +
> + if ( vec->op == XEN_VM_EVENT_NG_GET_VERSION )
> + {
> + vec->u.version = VM_EVENT_INTERFACE_VERSION;
> + return 0;
> + }
> +
> + if ( unlikely(d == NULL) )
> + return -ESRCH;
> +
> + rc = xsm_vm_event_control(XSM_PRIV, d, vec->type, vec->op);
> + if ( rc )
> + return rc;
> +
> + if ( unlikely(d == current->domain) ) /* no domain_pause() */
> + {
> + gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n");
> + return -EINVAL;
> + }
> +
> + if ( unlikely(d->is_dying) )
> + {
> + gdprintk(XENLOG_INFO, "Ignoring memory event op on dying domain
> %u\n",
> + d->domain_id);
> + return 0;
> + }
> +
> + if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
> + {
> + gdprintk(XENLOG_INFO,
> + "Memory event op on a domain (%u) with no vcpus\n",
> + d->domain_id);
> + return -EINVAL;
> + }
> +
> + switch ( vec->type )
> + {
> + case XEN_VM_EVENT_TYPE_MONITOR:
> + {
> + rc = -EINVAL;
> +
> + switch ( vec-> op)
> + {
> + case XEN_VM_EVENT_NG_CREATE:
> + /* domain_pause() not required here, see XSA-99 */
> + rc = arch_monitor_init_domain(d);
> + if ( rc )
> + break;
> + rc = vm_event_channels_create(d, vec, &d->vm_event_monitor,
> + _VPF_mem_access, monitor_notification);
> + break;
> +
> + case XEN_VM_EVENT_NG_DESTROY:
> + if ( !vm_event_check(d->vm_event_monitor) )
> + break;
> + domain_pause(d);
> + rc = vm_event_channels_destroy(&d->vm_event_monitor);
> + arch_monitor_cleanup_domain(d);
> + domain_unpause(d);
> + break;
> +
> + case XEN_VM_EVENT_NG_SET_STATE:
> + if ( !vm_event_check(d->vm_event_monitor) )
> + break;
> + domain_pause(d);
> + to_channels(d->vm_event_monitor)->enabled = !!vec->u.enabled;
> + domain_unpause(d);
> + rc = 0;
> + break;
> +
> + default:
> + rc = -ENOSYS;
> + }
> + break;
> + }
> +
> +#ifdef CONFIG_HAS_MEM_PAGING
> + case XEN_VM_EVENT_TYPE_PAGING:
> +#endif
> +
> +#ifdef CONFIG_HAS_MEM_SHARING
> + case XEN_VM_EVENT_TYPE_SHARING:
> +#endif
These are unnecessary, as they don't deviate from the default.
~Andrew
> +
> + default:
> + rc = -ENOSYS;
> + }
> +
> + return rc;
> +}
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |