aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-06-01 14:44:07 +0000
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-06-01 14:44:07 +0000
commit03249160f664e35ddef7b71c76617decc5dce789 (patch)
treee1b5930d3b9d90796712e1bb151028f09585e387
parente18f79780a71d716d2499ae0a9132cbf7273a121 (diff)
downloadxen-03249160f664e35ddef7b71c76617decc5dce789.tar.gz
xen-03249160f664e35ddef7b71c76617decc5dce789.tar.bz2
xen-03249160f664e35ddef7b71c76617decc5dce789.zip
bitkeeper revision 1.1628 (429dc9b7MTwsBkscbFS1sK8SbwJhdg)
Fix domain shutdown so that the new status, and notification to domain0, occur *after* the domain is fully descheduled and its execution state synchronised. Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c5
-rw-r--r--tools/libxc/xc_domain.c7
-rw-r--r--xen/arch/ia64/xenmisc.c3
-rw-r--r--xen/arch/x86/mm.c18
-rw-r--r--xen/common/dom0_ops.c1
-rw-r--r--xen/common/domain.c86
-rw-r--r--xen/common/schedule.c12
-rw-r--r--xen/include/asm-x86/mm.h17
-rw-r--r--xen/include/public/dom0_ops.h3
-rw-r--r--xen/include/xen/mm.h4
-rw-r--r--xen/include/xen/sched.h11
-rw-r--r--xen/include/xen/softirq.h3
12 files changed, 112 insertions, 58 deletions
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
index e2c72f8798..015c4f1938 100644
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
+++ b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
@@ -42,8 +42,7 @@ int (*myxcwait)(int domain, int *status, int options) ;
#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
-#define DOMFLAGS_CRASHED (1<<1) /* Crashed domain; frozen for postmortem. */
-#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut itself down. */
+#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
@@ -220,7 +219,7 @@ linux_wait (char *status)
if (myxcwait(current_domain, &w, 0))
return -1;
- if (w & (DOMFLAGS_CRASHED|DOMFLAGS_DYING)) {
+ if (w & (DOMFLAGS_SHUTDOWN|DOMFLAGS_DYING)) {
*status = 'W';
return 0;
}
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index b51c1c6088..8f0bba3216 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -86,7 +86,6 @@ int xc_domain_getinfo(int xc_handle,
info->domid = (u16)op.u.getdomaininfo.domain;
info->dying = !!(op.u.getdomaininfo.flags & DOMFLAGS_DYING);
- info->crashed = !!(op.u.getdomaininfo.flags & DOMFLAGS_CRASHED);
info->shutdown = !!(op.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN);
info->paused = !!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED);
info->blocked = !!(op.u.getdomaininfo.flags & DOMFLAGS_BLOCKED);
@@ -96,6 +95,12 @@ int xc_domain_getinfo(int xc_handle,
(op.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) &
DOMFLAGS_SHUTDOWNMASK;
+ if ( info->shutdown && (info->shutdown_reason == SHUTDOWN_crash) )
+ {
+ info->shutdown = 0;
+ info->crashed = 1;
+ }
+
info->nr_pages = op.u.getdomaininfo.tot_pages;
info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT);
info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
diff --git a/xen/arch/ia64/xenmisc.c b/xen/arch/ia64/xenmisc.c
index c4630bd7fd..e82dd8482d 100644
--- a/xen/arch/ia64/xenmisc.c
+++ b/xen/arch/ia64/xenmisc.c
@@ -304,7 +304,8 @@ loop:
printf(buf);
if (regs) show_registers(regs);
domain_pause_by_systemcontroller(current->domain);
- set_bit(_DOMF_crashed, ed->domain->domain_flags);
+ ed->domain->shutdown_code = SHUTDOWN_crash;
+ set_bit(_DOMF_shutdown, ed->domain->domain_flags);
if (ed->domain->domain_id == 0) {
int i = 1000000000L;
// if domain0 crashes, just periodically print out panic
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 872fa49e5f..8a60d435ee 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2971,6 +2971,24 @@ void ptwr_destroy(struct domain *d)
free_xenheap_page((unsigned long)d->arch.ptwr[PTWR_PT_INACTIVE].page);
}
+void cleanup_writable_pagetable(struct domain *d)
+{
+ if ( unlikely(!VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
+ return;
+
+ if ( unlikely(shadow_mode_enabled(d)) )
+ {
+ shadow_sync_all(d);
+ }
+ else
+ {
+ if ( d->arch.ptwr[PTWR_PT_ACTIVE].l1va )
+ ptwr_flush(d, PTWR_PT_ACTIVE);
+ if ( d->arch.ptwr[PTWR_PT_INACTIVE].l1va )
+ ptwr_flush(d, PTWR_PT_INACTIVE);
+ }
+}
+
int map_pages_to_xen(
unsigned long virt,
unsigned long pfn,
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index 1e5bcf5cf8..aae2a1172c 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -353,7 +353,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
op->u.getdomaininfo.flags = flags |
((d->domain_flags & DOMF_dying) ? DOMFLAGS_DYING : 0) |
- ((d->domain_flags & DOMF_crashed) ? DOMFLAGS_CRASHED : 0) |
((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 709240e202..fd32c54ac5 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -134,11 +134,7 @@ void domain_crash(void)
show_registers(guest_cpu_user_regs());
#endif
- set_bit(_DOMF_crashed, &d->domain_flags);
-
- send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC);
-
- raise_softirq(SCHEDULE_SOFTIRQ);
+ domain_shutdown(SHUTDOWN_crash);
}
@@ -150,9 +146,49 @@ void domain_crash_synchronous(void)
}
+static struct domain *domain_shuttingdown[NR_CPUS];
+
+static void domain_shutdown_finalise(void)
+{
+ struct domain *d;
+ struct exec_domain *ed;
+
+ d = domain_shuttingdown[smp_processor_id()];
+ domain_shuttingdown[smp_processor_id()] = NULL;
+
+ BUG_ON(d == NULL);
+ BUG_ON(d == current->domain);
+ BUG_ON(!test_bit(_DOMF_shuttingdown, &d->domain_flags));
+ BUG_ON(test_bit(_DOMF_shutdown, &d->domain_flags));
+
+ /* Make sure that every vcpu is descheduled before we finalise. */
+ for_each_exec_domain ( d, ed )
+ while ( test_bit(_VCPUF_running, &ed->vcpu_flags) )
+ cpu_relax();
+
+ sync_lazy_execstate_cpuset(d->cpuset);
+ BUG_ON(d->cpuset != 0);
+
+ sync_pagetable_state(d);
+
+ set_bit(_DOMF_shutdown, &d->domain_flags);
+ clear_bit(_DOMF_shuttingdown, &d->domain_flags);
+
+ send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC);
+}
+
+static __init int domain_shutdown_finaliser_init(void)
+{
+ open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
+ return 0;
+}
+__initcall(domain_shutdown_finaliser_init);
+
+
void domain_shutdown(u8 reason)
{
struct domain *d = current->domain;
+ struct exec_domain *ed;
if ( d->domain_id == 0 )
{
@@ -173,14 +209,18 @@ void domain_shutdown(u8 reason)
}
}
- if ( (d->shutdown_code = reason) == SHUTDOWN_crash )
- set_bit(_DOMF_crashed, &d->domain_flags);
- else
- set_bit(_DOMF_shutdown, &d->domain_flags);
-
- send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC);
+ /* Mark the domain as shutting down. */
+ d->shutdown_code = reason;
+ if ( !test_and_set_bit(_DOMF_shuttingdown, &d->domain_flags) )
+ {
+ /* This vcpu won the race to finalise the shutdown. */
+ domain_shuttingdown[smp_processor_id()] = d;
+ raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
+ }
- raise_softirq(SCHEDULE_SOFTIRQ);
+ /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
+ for_each_exec_domain ( d, ed )
+ domain_sleep_nosync(ed);
}
@@ -190,8 +230,7 @@ void domain_destruct(struct domain *d)
struct domain **pd;
atomic_t old, new;
- if ( !test_bit(_DOMF_dying, &d->domain_flags) )
- BUG();
+ BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
/* May be already destructed, or get_domain() can race us. */
_atomic_set(old, 0);
@@ -225,10 +264,9 @@ void domain_destruct(struct domain *d)
void exec_domain_pause(struct exec_domain *ed)
{
- ASSERT(ed != current);
+ BUG_ON(ed == current);
atomic_inc(&ed->pausecnt);
- domain_sleep(ed);
- sync_lazy_execstate_cpuset(ed->domain->cpuset & (1UL << ed->processor));
+ domain_sleep_sync(ed);
}
void domain_pause(struct domain *d)
@@ -237,17 +275,15 @@ void domain_pause(struct domain *d)
for_each_exec_domain( d, ed )
{
- ASSERT(ed != current);
+ BUG_ON(ed == current);
atomic_inc(&ed->pausecnt);
- domain_sleep(ed);
+ domain_sleep_sync(ed);
}
-
- sync_lazy_execstate_cpuset(d->cpuset);
}
void exec_domain_unpause(struct exec_domain *ed)
{
- ASSERT(ed != current);
+ BUG_ON(ed == current);
if ( atomic_dec_and_test(&ed->pausecnt) )
domain_wake(ed);
}
@@ -266,12 +302,10 @@ void domain_pause_by_systemcontroller(struct domain *d)
for_each_exec_domain ( d, ed )
{
- ASSERT(ed != current);
+ BUG_ON(ed == current);
if ( !test_and_set_bit(_VCPUF_ctrl_pause, &ed->vcpu_flags) )
- domain_sleep(ed);
+ domain_sleep_sync(ed);
}
-
- sync_lazy_execstate_cpuset(d->cpuset);
}
void domain_unpause_by_systemcontroller(struct domain *d)
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index 1e5df627d1..7707ea03af 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -190,7 +190,7 @@ void sched_rem_domain(struct exec_domain *ed)
TRACE_2D(TRC_SCHED_DOM_REM, ed->domain->domain_id, ed->vcpu_id);
}
-void domain_sleep(struct exec_domain *ed)
+void domain_sleep_nosync(struct exec_domain *ed)
{
unsigned long flags;
@@ -200,10 +200,16 @@ void domain_sleep(struct exec_domain *ed)
spin_unlock_irqrestore(&schedule_data[ed->processor].schedule_lock, flags);
TRACE_2D(TRC_SCHED_SLEEP, ed->domain->domain_id, ed->vcpu_id);
-
- /* Synchronous. */
+}
+
+void domain_sleep_sync(struct exec_domain *ed)
+{
+ domain_sleep_nosync(ed);
+
while ( test_bit(_VCPUF_running, &ed->vcpu_flags) && !domain_runnable(ed) )
cpu_relax();
+
+ sync_lazy_execstate_cpuset(ed->domain->cpuset & (1UL << ed->processor));
}
void domain_wake(struct exec_domain *ed)
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index ac0d3cd40b..5c7f91f127 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -314,21 +314,8 @@ void ptwr_flush(struct domain *, const int);
int ptwr_do_page_fault(struct domain *, unsigned long);
int revalidate_l1(struct domain *, l1_pgentry_t *, l1_pgentry_t *);
-#define cleanup_writable_pagetable(_d) \
- do { \
- if ( likely(VM_ASSIST((_d), VMASST_TYPE_writable_pagetables)) ) \
- { \
- if ( likely(!shadow_mode_enabled(_d)) ) \
- { \
- if ( (_d)->arch.ptwr[PTWR_PT_ACTIVE].l1va ) \
- ptwr_flush((_d), PTWR_PT_ACTIVE); \
- if ( (_d)->arch.ptwr[PTWR_PT_INACTIVE].l1va ) \
- ptwr_flush((_d), PTWR_PT_INACTIVE); \
- } \
- else \
- shadow_sync_all(_d); \
- } \
- } while ( 0 )
+void cleanup_writable_pagetable(struct domain *d);
+#define sync_pagetable_state(d) cleanup_writable_pagetable(d)
int audit_adjust_pgtables(struct domain *d, int dir, int noisy);
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index 76bd18e079..4c3d5271a2 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -72,8 +72,7 @@ typedef struct {
domid_t domain; /* NB. IN/OUT variable. */
/* OUT variables. */
#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
-#define DOMFLAGS_CRASHED (1<<1) /* Crashed domain; frozen for postmortem. */
-#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut itself down. */
+#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index 807987045f..4e7f570643 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -48,4 +48,8 @@ extern struct list_head page_scrub_list;
#include <asm/mm.h>
+#ifndef sync_pagetable_state
+#define sync_pagetable_state(d) ((void)0)
+#endif
+
#endif /* __XEN_MM_H__ */
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 0462fda5c1..e1af30ed2d 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -255,7 +255,8 @@ long sched_ctl(struct sched_ctl_cmd *);
long sched_adjdom(struct sched_adjdom_cmd *);
int sched_id();
void domain_wake(struct exec_domain *d);
-void domain_sleep(struct exec_domain *d);
+void domain_sleep_nosync(struct exec_domain *d);
+void domain_sleep_sync(struct exec_domain *d);
/*
* Force loading of currently-executing domain state on the specified set
@@ -375,9 +376,9 @@ extern struct domain *domain_list;
/* Guest shut itself down for some reason. */
#define _DOMF_shutdown 4
#define DOMF_shutdown (1UL<<_DOMF_shutdown)
- /* Domain has crashed and cannot continue to execute. */
-#define _DOMF_crashed 5
-#define DOMF_crashed (1UL<<_DOMF_crashed)
+ /* Guest is in process of shutting itself down (becomes DOMF_shutdown). */
+#define _DOMF_shuttingdown 5
+#define DOMF_shuttingdown (1UL<<_DOMF_shuttingdown)
/* Death rattle. */
#define _DOMF_dying 6
#define DOMF_dying (1UL<<_DOMF_dying)
@@ -386,7 +387,7 @@ static inline int domain_runnable(struct exec_domain *ed)
{
return ( (atomic_read(&ed->pausecnt) == 0) &&
!(ed->vcpu_flags & (VCPUF_blocked|VCPUF_ctrl_pause)) &&
- !(ed->domain->domain_flags & (DOMF_shutdown|DOMF_crashed)) );
+ !(ed->domain->domain_flags & (DOMF_shutdown|DOMF_shuttingdown)) );
}
void exec_domain_pause(struct exec_domain *ed);
diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h
index a538540247..de3480482a 100644
--- a/xen/include/xen/softirq.h
+++ b/xen/include/xen/softirq.h
@@ -8,7 +8,8 @@
#define KEYPRESS_SOFTIRQ 3
#define NMI_SOFTIRQ 4
#define PAGE_SCRUB_SOFTIRQ 5
-#define NR_SOFTIRQS 6
+#define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6
+#define NR_SOFTIRQS 7
#ifndef __ASSEMBLY__