[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.