[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] xen: Allow vcpus to defer a shutdown request across critical
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1175597050 -3600 # Node ID a1b17c48fb403e9b8fd4fe136198eafa126a5cf7 # Parent 45e9f6d7e422156ec36d64dea817af2fb659ec1a xen: Allow vcpus to defer a shutdown request across critical asynchronous operations (in particular, hvm ioreq requests). Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- xen/arch/x86/hvm/hvm.c | 3 + xen/arch/x86/hvm/io.c | 11 ++- xen/arch/x86/mm.c | 3 - xen/arch/x86/mm/shadow/multi.c | 4 - xen/common/domain.c | 118 +++++++++++++++++++++++++++++++++++++---- xen/common/domctl.c | 5 - xen/include/xen/sched.h | 12 +++- 7 files changed, 136 insertions(+), 20 deletions(-) diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/arch/x86/hvm/hvm.c Tue Apr 03 11:44:10 2007 +0100 @@ -372,6 +372,9 @@ void hvm_send_assist_req(struct vcpu *v) void hvm_send_assist_req(struct vcpu *v) { ioreq_t *p; + + if ( unlikely(!vcpu_start_shutdown_deferral(v)) ) + return; /* implicitly bins the i/o operation */ p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; if ( unlikely(p->state != STATE_IOREQ_NONE) ) diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/arch/x86/hvm/io.c Tue Apr 03 11:44:10 2007 +0100 @@ -771,10 +771,11 @@ void hvm_io_assist(struct vcpu *v) struct cpu_user_regs *regs; struct hvm_io_op *io_opp; unsigned long gmfn; + struct domain *d = v->domain; io_opp = &v->arch.hvm_vcpu.io_op; regs = &io_opp->io_context; - vio = get_vio(v->domain, v->vcpu_id); + vio = get_vio(d, v->vcpu_id); p = &vio->vp_ioreq; if ( p->state != STATE_IORESP_READY ) @@ -797,11 +798,13 @@ void hvm_io_assist(struct vcpu *v) memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); /* Has memory been dirtied? */ - if ( p->dir == IOREQ_READ && p->data_is_ptr ) + if ( (p->dir == IOREQ_READ) && p->data_is_ptr ) { gmfn = get_mfn_from_gpfn(paging_gva_to_gfn(v, p->data)); - mark_dirty(v->domain, gmfn); - } + mark_dirty(d, gmfn); + } + + vcpu_end_shutdown_deferral(v); } /* diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/arch/x86/mm.c Tue Apr 03 11:44:10 2007 +0100 @@ -806,7 +806,8 @@ void put_page_from_l1e(l1_pgentry_t l1e, * (Note that the undestroyable active grants are not a security hole in * Xen. All active grants can safely be cleaned up when the domain dies.) */ - if ( (l1e_get_flags(l1e) & _PAGE_GNTTAB) && !d->is_shutdown && !d->is_dying ) + if ( (l1e_get_flags(l1e) & _PAGE_GNTTAB) && + !d->is_shutting_down && !d->is_dying ) { MEM_LOG("Attempt to implicitly unmap a granted PTE %" PRIpte, l1e_get_intpte(l1e)); diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/arch/x86/mm/shadow/multi.c --- a/xen/arch/x86/mm/shadow/multi.c Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/arch/x86/mm/shadow/multi.c Tue Apr 03 11:44:10 2007 +0100 @@ -2823,8 +2823,8 @@ static int sh_page_fault(struct vcpu *v, * are OK, this can only have been caused by a failed * shadow_set_l*e(), which will have crashed the guest. * Get out of the fault handler immediately. */ - ASSERT(d->is_shutdown); - unmap_walk(v, &gw); + ASSERT(d->is_shutting_down); + unmap_walk(v, &gw); shadow_unlock(d); return 0; } diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/common/domain.c --- a/xen/common/domain.c Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/common/domain.c Tue Apr 03 11:44:10 2007 +0100 @@ -59,6 +59,7 @@ struct domain *alloc_domain(domid_t domi atomic_set(&d->refcnt, 1); spin_lock_init(&d->big_lock); spin_lock_init(&d->page_alloc_lock); + spin_lock_init(&d->shutdown_lock); INIT_LIST_HEAD(&d->page_list); INIT_LIST_HEAD(&d->xenpage_list); @@ -83,6 +84,45 @@ void free_domain(struct domain *d) xfree(d); } +static void __domain_finalise_shutdown(struct domain *d) +{ + struct vcpu *v; + + BUG_ON(!spin_is_locked(&d->shutdown_lock)); + + if ( d->is_shut_down ) + return; + + for_each_vcpu ( d, v ) + if ( !v->paused_for_shutdown ) + return; + + d->is_shut_down = 1; + + for_each_vcpu ( d, v ) + vcpu_sleep_nosync(v); + + send_guest_global_virq(dom0, VIRQ_DOM_EXC); +} + +static void vcpu_check_shutdown(struct vcpu *v) +{ + struct domain *d = v->domain; + + spin_lock(&d->shutdown_lock); + + if ( d->is_shutting_down ) + { + if ( !v->paused_for_shutdown ) + atomic_inc(&v->pause_count); + v->paused_for_shutdown = 1; + v->defer_shutdown = 0; + __domain_finalise_shutdown(d); + } + + spin_unlock(&d->shutdown_lock); +} + struct vcpu *alloc_vcpu( struct domain *d, unsigned int vcpu_id, unsigned int cpu_id) { @@ -121,6 +161,9 @@ struct vcpu *alloc_vcpu( d->vcpu[vcpu_id] = v; if ( vcpu_id != 0 ) d->vcpu[v->vcpu_id-1]->next_in_list = v; + + /* Must be called after making new vcpu visible to for_each_vcpu(). */ + vcpu_check_shutdown(v); return v; } @@ -286,7 +329,7 @@ void domain_kill(struct domain *d) void __domain_crash(struct domain *d) { - if ( d->is_shutdown ) + if ( d->is_shutting_down ) { /* Print nothing: the domain is already shutting down. */ } @@ -335,16 +378,73 @@ void domain_shutdown(struct domain *d, u if ( d->domain_id == 0 ) dom0_shutdown(reason); - atomic_inc(&d->pause_count); - if ( !xchg(&d->is_shutdown, 1) ) - d->shutdown_code = reason; - else - domain_unpause(d); + spin_lock(&d->shutdown_lock); + + if ( d->is_shutting_down ) + { + spin_unlock(&d->shutdown_lock); + return; + } + + d->is_shutting_down = 1; + d->shutdown_code = reason; + + smp_mb(); /* set shutdown status /then/ check for per-cpu deferrals */ for_each_vcpu ( d, v ) - vcpu_sleep_nosync(v); - - send_guest_global_virq(dom0, VIRQ_DOM_EXC); + { + if ( v->defer_shutdown ) + continue; + atomic_inc(&v->pause_count); + v->paused_for_shutdown = 1; + } + + __domain_finalise_shutdown(d); + + spin_unlock(&d->shutdown_lock); +} + +void domain_resume(struct domain *d) +{ + struct vcpu *v; + + /* + * Some code paths assume that shutdown status does not get reset under + * their feet (e.g., some assertions make this assumption). + */ + domain_pause(d); + + spin_lock(&d->shutdown_lock); + + d->is_shutting_down = d->is_shut_down = 0; + + for_each_vcpu ( d, v ) + { + if ( v->paused_for_shutdown ) + vcpu_unpause(v); + v->paused_for_shutdown = 0; + } + + spin_unlock(&d->shutdown_lock); + + domain_unpause(d); +} + +int vcpu_start_shutdown_deferral(struct vcpu *v) +{ + v->defer_shutdown = 1; + smp_mb(); /* set deferral status /then/ check for shutdown */ + if ( unlikely(v->domain->is_shutting_down) ) + vcpu_check_shutdown(v); + return v->defer_shutdown; +} + +void vcpu_end_shutdown_deferral(struct vcpu *v) +{ + v->defer_shutdown = 0; + smp_mb(); /* clear deferral status /then/ check for shutdown */ + if ( unlikely(v->domain->is_shutting_down) ) + vcpu_check_shutdown(v); } void domain_pause_for_debugger(void) diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/common/domctl.c --- a/xen/common/domctl.c Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/common/domctl.c Tue Apr 03 11:44:10 2007 +0100 @@ -115,7 +115,7 @@ void getdomaininfo(struct domain *d, str info->flags = flags | (d->is_dying ? XEN_DOMINF_dying : 0) | - (d->is_shutdown ? XEN_DOMINF_shutdown : 0) | + (d->is_shut_down ? XEN_DOMINF_shutdown : 0) | (d->is_paused_by_controller ? XEN_DOMINF_paused : 0) | d->shutdown_code << XEN_DOMINF_shutdownshift; @@ -287,8 +287,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc if ( d == NULL ) break; - if ( xchg(&d->is_shutdown, 0) ) - domain_unpause(d); + domain_resume(d); rcu_unlock_domain(d); ret = 0; } diff -r 45e9f6d7e422 -r a1b17c48fb40 xen/include/xen/sched.h --- a/xen/include/xen/sched.h Tue Apr 03 10:36:31 2007 +0100 +++ b/xen/include/xen/sched.h Tue Apr 03 11:44:10 2007 +0100 @@ -114,6 +114,10 @@ struct vcpu bool_t nmi_pending; /* Avoid NMI reentry by allowing NMIs to be masked for short periods. */ bool_t nmi_masked; + /* Require shutdown to be deferred for some asynchronous operation? */ + bool_t defer_shutdown; + /* VCPU is paused following shutdown request (d->is_shutting_down)? */ + bool_t paused_for_shutdown; unsigned long pause_flags; atomic_t pause_count; @@ -193,7 +197,9 @@ struct domain bool_t is_paused_by_controller; /* Guest has shut down (inc. reason code)? */ - bool_t is_shutdown; + spinlock_t shutdown_lock; + bool_t is_shutting_down; /* in process of shutting down? */ + bool_t is_shut_down; /* fully shut down? */ int shutdown_code; atomic_t pause_count; @@ -331,7 +337,11 @@ void domain_destroy(struct domain *d); void domain_destroy(struct domain *d); void domain_kill(struct domain *d); void domain_shutdown(struct domain *d, u8 reason); +void domain_resume(struct domain *d); void domain_pause_for_debugger(void); + +int vcpu_start_shutdown_deferral(struct vcpu *v); +void vcpu_end_shutdown_deferral(struct vcpu *v); /* * Mark specified domain as crashed. This function always returns, even if the _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |