[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 |