[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 2/5] ioreq-server: create basic ioreq server abstraction.
On 30/01/14 14:19, Paul Durrant wrote: > Collect together data structures concerning device emulation together into > a new struct hvm_ioreq_server. > > Code that deals with the shared and buffered ioreq pages is extracted from > functions such as hvm_domain_initialise, hvm_vcpu_initialise and do_hvm_op > and consolidated into a set of hvm_ioreq_server_XXX functions. > > Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> > --- > xen/arch/x86/hvm/hvm.c | 318 > ++++++++++++++++++++++++++------------ > xen/include/asm-x86/hvm/domain.h | 9 +- > xen/include/asm-x86/hvm/vcpu.h | 2 +- > 3 files changed, 229 insertions(+), 100 deletions(-) > > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index 71a44db..a0eaadb 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -345,16 +345,16 @@ void hvm_migrate_pirqs(struct vcpu *v) > spin_unlock(&d->event_lock); > } > > -static ioreq_t *get_ioreq(struct vcpu *v) > +static ioreq_t *get_ioreq(struct hvm_ioreq_server *s, int id) > { > - struct domain *d = v->domain; > - shared_iopage_t *p = d->arch.hvm_domain.ioreq.va; > - ASSERT((v == current) || spin_is_locked(&d->arch.hvm_domain.ioreq.lock)); > - return p ? &p->vcpu_ioreq[v->vcpu_id] : NULL; > + shared_iopage_t *p = s->ioreq.va; > + ASSERT(p != NULL); > + return &p->vcpu_ioreq[id]; > } > > void hvm_do_resume(struct vcpu *v) > { > + struct hvm_ioreq_server *s; > ioreq_t *p; > > check_wakeup_from_wait(); > @@ -362,10 +362,14 @@ void hvm_do_resume(struct vcpu *v) > if ( is_hvm_vcpu(v) ) > pt_restore_timer(v); > > - /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ > - if ( !(p = get_ioreq(v)) ) > + s = v->arch.hvm_vcpu.ioreq_server; This assignment can be part of the declaration of 's' (and likewise in most later examples). > + v->arch.hvm_vcpu.ioreq_server = NULL; > + > + if ( !s ) > goto check_inject_trap; > > + /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ > + p = get_ioreq(s, v->vcpu_id); > while ( p->state != STATE_IOREQ_NONE ) > { > switch ( p->state ) > @@ -375,7 +379,7 @@ void hvm_do_resume(struct vcpu *v) > break; > case STATE_IOREQ_READY: /* IOREQ_{READY,INPROCESS} -> IORESP_READY > */ > case STATE_IOREQ_INPROCESS: > - wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port, > + wait_on_xen_event_channel(p->vp_eport, > (p->state != STATE_IOREQ_READY) && > (p->state != STATE_IOREQ_INPROCESS)); > break; > @@ -398,7 +402,6 @@ void hvm_do_resume(struct vcpu *v) > static void hvm_init_ioreq_page( > struct domain *d, struct hvm_ioreq_page *iorp) > { > - memset(iorp, 0, sizeof(*iorp)); Is it worth keeping this function? the two back to back domain_pause()'s from the callers are redundant. > spin_lock_init(&iorp->lock); > domain_pause(d); > } > @@ -541,6 +544,167 @@ static int handle_pvh_io( > return X86EMUL_OKAY; > } > > +static int hvm_init_ioreq_server(struct domain *d) > +{ > + struct hvm_ioreq_server *s; > + int i; > + > + s = xzalloc(struct hvm_ioreq_server); > + if ( !s ) > + return -ENOMEM; > + > + s->domain = d; > + > + for ( i = 0; i < MAX_HVM_VCPUS; i++ ) > + s->ioreq_evtchn[i] = -1; > + s->buf_ioreq_evtchn = -1; > + > + hvm_init_ioreq_page(d, &s->ioreq); > + hvm_init_ioreq_page(d, &s->buf_ioreq); > + > + d->arch.hvm_domain.ioreq_server = s; > + return 0; > +} > + > +static void hvm_deinit_ioreq_server(struct domain *d) > +{ > + struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + > + hvm_destroy_ioreq_page(d, &s->ioreq); > + hvm_destroy_ioreq_page(d, &s->buf_ioreq); > + > + xfree(s); > +} > + > +static void hvm_update_ioreq_server_evtchn(struct hvm_ioreq_server *s) > +{ > + struct domain *d = s->domain; > + > + if ( s->ioreq.va != NULL ) > + { > + shared_iopage_t *p = s->ioreq.va; > + struct vcpu *v; > + > + for_each_vcpu ( d, v ) > + p->vcpu_ioreq[v->vcpu_id].vp_eport = s->ioreq_evtchn[v->vcpu_id]; > + } > +} > + > +static int hvm_ioreq_server_add_vcpu(struct hvm_ioreq_server *s, struct vcpu > *v) > +{ > + int rc; > + > + /* Create ioreq event channel. */ > + rc = alloc_unbound_xen_event_channel(v, s->domid, NULL); > + if ( rc < 0 ) > + goto done; > + > + /* Register ioreq event channel. */ > + s->ioreq_evtchn[v->vcpu_id] = rc; > + > + if ( v->vcpu_id == 0 ) > + { > + /* Create bufioreq event channel. */ > + rc = alloc_unbound_xen_event_channel(v, s->domid, NULL); > + if ( rc < 0 ) > + goto done; skipping hvm_update_ioreq_server_evtchn() even in the case of a successful ioreq event channel? > + > + s->buf_ioreq_evtchn = rc; > + } > + > + hvm_update_ioreq_server_evtchn(s); > + rc = 0; > + > +done: > + return rc; > +} > + > +static void hvm_ioreq_server_remove_vcpu(struct hvm_ioreq_server *s, struct > vcpu *v) > +{ > + if ( v->vcpu_id == 0 ) > + { > + if ( s->buf_ioreq_evtchn >= 0 ) > + { > + free_xen_event_channel(v, s->buf_ioreq_evtchn); > + s->buf_ioreq_evtchn = -1; > + } > + } > + > + if ( s->ioreq_evtchn[v->vcpu_id] >= 0 ) > + { > + free_xen_event_channel(v, s->ioreq_evtchn[v->vcpu_id]); > + s->ioreq_evtchn[v->vcpu_id] = -1; > + } > +} > + > +static int hvm_replace_event_channel(struct vcpu *v, domid_t remote_domid, > + int *p_port) > +{ > + int old_port, new_port; > + > + new_port = alloc_unbound_xen_event_channel(v, remote_domid, NULL); > + if ( new_port < 0 ) > + return new_port; > + > + /* xchg() ensures that only we call free_xen_event_channel(). */ > + old_port = xchg(p_port, new_port); > + free_xen_event_channel(v, old_port); > + return 0; > +} > + > +static int hvm_set_ioreq_server_domid(struct hvm_ioreq_server *s, domid_t > domid) > +{ > + struct domain *d = s->domain; > + struct vcpu *v; > + int rc = 0; > + > + domain_pause(d); > + > + if ( d->vcpu[0] ) > + { > + rc = hvm_replace_event_channel(d->vcpu[0], domid, > &s->buf_ioreq_evtchn); > + if ( rc < 0 ) > + goto done; > + } > + > + for_each_vcpu ( d, v ) > + { > + rc = hvm_replace_event_channel(v, domid, > &s->ioreq_evtchn[v->vcpu_id]); > + if ( rc < 0 ) > + goto done; > + } > + > + hvm_update_ioreq_server_evtchn(s); > + > + s->domid = domid; > + > +done: > + domain_unpause(d); > + > + return rc; > +} > + > +static int hvm_set_ioreq_server_pfn(struct hvm_ioreq_server *s, unsigned > long pfn) > +{ > + struct domain *d = s->domain; > + int rc; > + > + rc = hvm_set_ioreq_page(d, &s->ioreq, pfn); > + if ( rc < 0 ) > + return rc; > + > + hvm_update_ioreq_server_evtchn(s); > + > + return 0; > +} > + > +static int hvm_set_ioreq_server_buf_pfn(struct hvm_ioreq_server *s, unsigned > long pfn) > +{ > + struct domain *d = s->domain; > + > + return hvm_set_ioreq_page(d, &s->buf_ioreq, pfn); Double space. > +} > + > int hvm_domain_initialise(struct domain *d) > { > int rc; > @@ -608,17 +772,20 @@ int hvm_domain_initialise(struct domain *d) > > rtc_init(d); > > - hvm_init_ioreq_page(d, &d->arch.hvm_domain.ioreq); > - hvm_init_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); > + rc = hvm_init_ioreq_server(d); > + if ( rc != 0 ) > + goto fail2; > > register_portio_handler(d, 0xe9, 1, hvm_print_line); > > rc = hvm_funcs.domain_initialise(d); > if ( rc != 0 ) > - goto fail2; > + goto fail3; > > return 0; > > + fail3: > + hvm_deinit_ioreq_server(d); > fail2: > rtc_deinit(d); > stdvga_deinit(d); > @@ -642,8 +809,7 @@ void hvm_domain_relinquish_resources(struct domain *d) > if ( hvm_funcs.nhvm_domain_relinquish_resources ) > hvm_funcs.nhvm_domain_relinquish_resources(d); > > - hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq); > - hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); > + hvm_deinit_ioreq_server(d); > > msixtbl_pt_cleanup(d); > > @@ -1155,7 +1321,7 @@ int hvm_vcpu_initialise(struct vcpu *v) > { > int rc; > struct domain *d = v->domain; > - domid_t dm_domid; > + struct hvm_ioreq_server *s; > > hvm_asid_flush_vcpu(v); > > @@ -1198,30 +1364,12 @@ int hvm_vcpu_initialise(struct vcpu *v) > && (rc = nestedhvm_vcpu_initialise(v)) < 0 ) /* teardown: > nestedhvm_vcpu_destroy */ > goto fail5; > > - dm_domid = d->arch.hvm_domain.params[HVM_PARAM_DM_DOMAIN]; > + s = d->arch.hvm_domain.ioreq_server; > > - /* Create ioreq event channel. */ > - rc = alloc_unbound_xen_event_channel(v, dm_domid, NULL); /* teardown: > none */ > + rc = hvm_ioreq_server_add_vcpu(s, v); > if ( rc < 0 ) > goto fail6; > > - /* Register ioreq event channel. */ > - v->arch.hvm_vcpu.xen_port = rc; > - > - if ( v->vcpu_id == 0 ) > - { > - /* Create bufioreq event channel. */ > - rc = alloc_unbound_xen_event_channel(v, dm_domid, NULL); /* > teardown: none */ > - if ( rc < 0 ) > - goto fail6; > - d->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN] = rc; > - } > - > - spin_lock(&d->arch.hvm_domain.ioreq.lock); > - if ( d->arch.hvm_domain.ioreq.va != NULL ) > - get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; > - spin_unlock(&d->arch.hvm_domain.ioreq.lock); > - > if ( v->vcpu_id == 0 ) > { > /* NB. All these really belong in hvm_domain_initialise(). */ > @@ -1255,6 +1403,11 @@ int hvm_vcpu_initialise(struct vcpu *v) > > void hvm_vcpu_destroy(struct vcpu *v) > { > + struct domain *d = v->domain; > + struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + > + hvm_ioreq_server_remove_vcpu(s, v); > + > nestedhvm_vcpu_destroy(v); > > free_compat_arg_xlat(v); > @@ -1266,9 +1419,6 @@ void hvm_vcpu_destroy(struct vcpu *v) > vlapic_destroy(v); > > hvm_funcs.vcpu_destroy(v); > - > - /* Event channel is already freed by evtchn_destroy(). */ > - /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/ > } > > void hvm_vcpu_down(struct vcpu *v) > @@ -1298,8 +1448,10 @@ void hvm_vcpu_down(struct vcpu *v) > int hvm_buffered_io_send(ioreq_t *p) > { > struct vcpu *v = current; > - struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq; > - buffered_iopage_t *pg = iorp->va; > + struct domain *d = v->domain; > + struct hvm_ioreq_server *s; > + struct hvm_ioreq_page *iorp; > + buffered_iopage_t *pg; > buf_ioreq_t bp; > /* Timeoffset sends 64b data, but no address. Use two consecutive slots. > */ > int qw = 0; > @@ -1307,6 +1459,13 @@ int hvm_buffered_io_send(ioreq_t *p) > /* Ensure buffered_iopage fits in a page */ > BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE); > > + s = d->arch.hvm_domain.ioreq_server; > + if ( !s ) > + return 0; > + > + iorp = &s->buf_ioreq; > + pg = iorp->va; > + > /* > * Return 0 for the cases we can't deal with: > * - 'addr' is only a 20-bit field, so we cannot address beyond 1MB > @@ -1367,8 +1526,7 @@ int hvm_buffered_io_send(ioreq_t *p) > wmb(); > pg->write_pointer += qw ? 2 : 1; > > - notify_via_xen_event_channel(v->domain, > - v->domain->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN]); > + notify_via_xen_event_channel(d, s->buf_ioreq_evtchn); > spin_unlock(&iorp->lock); > > return 1; > @@ -1376,22 +1534,29 @@ int hvm_buffered_io_send(ioreq_t *p) > > bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *proto_p) > { > + struct domain *d = v->domain; > + struct hvm_ioreq_server *s; > ioreq_t *p; > > if ( unlikely(!vcpu_start_shutdown_deferral(v)) ) > return 0; /* implicitly bins the i/o operation */ > > - if ( !(p = get_ioreq(v)) ) > + s = d->arch.hvm_domain.ioreq_server; > + if ( !s ) > return 0; > > + p = get_ioreq(s, v->vcpu_id); > + > if ( unlikely(p->state != STATE_IOREQ_NONE) ) > { > /* This indicates a bug in the device model. Crash the domain. */ > gdprintk(XENLOG_ERR, "Device model set bad IO state %d.\n", > p->state); > - domain_crash(v->domain); > + domain_crash(d); > return 0; > } > > + v->arch.hvm_vcpu.ioreq_server = s; > + > p->dir = proto_p->dir; > p->data_is_ptr = proto_p->data_is_ptr; > p->type = proto_p->type; > @@ -1401,14 +1566,14 @@ bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t > *proto_p) > p->df = proto_p->df; > p->data = proto_p->data; > > - prepare_wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port); > + prepare_wait_on_xen_event_channel(p->vp_eport); > > /* > * Following happens /after/ blocking and setting up ioreq contents. > * prepare_wait_on_xen_event_channel() is an implicit barrier. > */ > p->state = STATE_IOREQ_READY; > - notify_via_xen_event_channel(v->domain, v->arch.hvm_vcpu.xen_port); > + notify_via_xen_event_channel(d, p->vp_eport); > > return 1; > } > @@ -3995,21 +4160,6 @@ static int hvmop_flush_tlb_all(void) > return 0; > } > > -static int hvm_replace_event_channel(struct vcpu *v, domid_t remote_domid, > - int *p_port) > -{ > - int old_port, new_port; > - > - new_port = alloc_unbound_xen_event_channel(v, remote_domid, NULL); > - if ( new_port < 0 ) > - return new_port; > - > - /* xchg() ensures that only we call free_xen_event_channel(). */ > - old_port = xchg(p_port, new_port); > - free_xen_event_channel(v, old_port); > - return 0; > -} > - > long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) > > { > @@ -4022,7 +4172,7 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > case HVMOP_get_param: > { > struct xen_hvm_param a; > - struct hvm_ioreq_page *iorp; > + struct hvm_ioreq_server *s; > struct domain *d; > struct vcpu *v; > > @@ -4048,6 +4198,8 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > if ( rc ) > goto param_fail; > > + s = d->arch.hvm_domain.ioreq_server; > + This should be reduced in lexical scope, and I would have said that it can just be 'inlined' into each of the 4 uses later. > if ( op == HVMOP_set_param ) > { > rc = 0; > @@ -4055,19 +4207,10 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > switch ( a.index ) > { > case HVM_PARAM_IOREQ_PFN: > - iorp = &d->arch.hvm_domain.ioreq; > - if ( (rc = hvm_set_ioreq_page(d, iorp, a.value)) != 0 ) > - break; > - spin_lock(&iorp->lock); > - if ( iorp->va != NULL ) > - /* Initialise evtchn port info if VCPUs already created. > */ > - for_each_vcpu ( d, v ) > - get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; > - spin_unlock(&iorp->lock); > + rc = hvm_set_ioreq_server_pfn(s, a.value); > break; > case HVM_PARAM_BUFIOREQ_PFN: > - iorp = &d->arch.hvm_domain.buf_ioreq; > - rc = hvm_set_ioreq_page(d, iorp, a.value); > + rc = hvm_set_ioreq_server_buf_pfn(s, a.value); > break; > case HVM_PARAM_CALLBACK_IRQ: > hvm_set_callback_via(d, a.value); > @@ -4122,31 +4265,7 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > if ( a.value == DOMID_SELF ) > a.value = curr_d->domain_id; > > - rc = 0; > - domain_pause(d); /* safe to change per-vcpu xen_port */ > - if ( d->vcpu[0] ) > - rc = hvm_replace_event_channel(d->vcpu[0], a.value, > - (int > *)&d->vcpu[0]->domain->arch.hvm_domain.params > - [HVM_PARAM_BUFIOREQ_EVTCHN]); > - if ( rc ) > - { > - domain_unpause(d); > - break; > - } > - iorp = &d->arch.hvm_domain.ioreq; > - for_each_vcpu ( d, v ) > - { > - rc = hvm_replace_event_channel(v, a.value, > - > &v->arch.hvm_vcpu.xen_port); > - if ( rc ) > - break; > - > - spin_lock(&iorp->lock); > - if ( iorp->va != NULL ) > - get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; > - spin_unlock(&iorp->lock); > - } > - domain_unpause(d); > + rc = hvm_set_ioreq_server_domid(s, a.value); > break; > case HVM_PARAM_ACPI_S_STATE: > /* Not reflexive, as we must domain_pause(). */ > @@ -4241,6 +4360,9 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > { > switch ( a.index ) > { > + case HVM_PARAM_BUFIOREQ_EVTCHN: > + a.value = s->buf_ioreq_evtchn; > + break; > case HVM_PARAM_ACPI_S_STATE: > a.value = d->arch.hvm_domain.is_s3_suspended ? 3 : 0; > break; > diff --git a/xen/include/asm-x86/hvm/domain.h > b/xen/include/asm-x86/hvm/domain.h > index b1e3187..4c039f8 100644 > --- a/xen/include/asm-x86/hvm/domain.h > +++ b/xen/include/asm-x86/hvm/domain.h > @@ -41,10 +41,17 @@ struct hvm_ioreq_page { > void *va; > }; > > -struct hvm_domain { > +struct hvm_ioreq_server { > + struct domain *domain; > + domid_t domid; > struct hvm_ioreq_page ioreq; > + int ioreq_evtchn[MAX_HVM_VCPUS]; > struct hvm_ioreq_page buf_ioreq; > + int buf_ioreq_evtchn; > +}; > > +struct hvm_domain { > + struct hvm_ioreq_server *ioreq_server; > struct pl_time pl_time; > > struct hvm_io_handler *io_handler; > diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h > index 122ab0d..4c9d7ee 100644 > --- a/xen/include/asm-x86/hvm/vcpu.h > +++ b/xen/include/asm-x86/hvm/vcpu.h > @@ -138,7 +138,7 @@ struct hvm_vcpu { > spinlock_t tm_lock; > struct list_head tm_list; > > - int xen_port; > + struct hvm_ioreq_server *ioreq_server; > Why do both hvm_vcpu and hvm_domain need ioreq_server pointers? I cant spot anything which actually uses the vcpu one. ~Andrew > bool_t flag_dr_dirty; > bool_t debug_state_latch; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |