# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1215169224 -3600
# Node ID 14fd83fe71c3d3db1bd52736e161558f0f912e5c
# Parent 9cf72db44ee968de1c4a51de1e9aa91c841b6e6b
Add facility to get notification of domain suspend by event channel.
This event channel will be notified when the domain transitions to the
suspended state, which can be much faster than raising VIRQ_DOM_EXC
and waiting for the notification to be propagated via xenstore.
No attempt is made here to prevent multiple subscribers (last one
wins), or to detect that the subscriber has gone away. Userspace tools
should take care.
Signed-off-by: Brendan Cully <brendan@xxxxxxxxx>
---
tools/libxc/xc_domain.c | 11 +++++
tools/libxc/xenctrl.h | 6 +++
xen/arch/x86/traps.c | 74 ++++++++++++++++++++++++++++++++-----
xen/arch/x86/x86_32/traps.c | 4 ++
xen/arch/x86/x86_64/compat/traps.c | 4 ++
xen/arch/x86/x86_64/traps.c | 4 ++
xen/common/domain.c | 8 +++-
xen/common/domctl.c | 15 +++++++
xen/include/public/domctl.h | 8 ++++
xen/include/xen/sched.h | 6 +++
10 files changed, 130 insertions(+), 10 deletions(-)
diff -r 9cf72db44ee9 -r 14fd83fe71c3 tools/libxc/xc_domain.c
--- a/tools/libxc/xc_domain.c Fri Jul 04 11:54:21 2008 +0100
+++ b/tools/libxc/xc_domain.c Fri Jul 04 12:00:24 2008 +0100
@@ -981,6 +981,17 @@ int xc_domain_set_target(
return do_domctl(xc_handle, &domctl);
}
+int xc_dom_subscribe(int xc_handle, domid_t dom, evtchn_port_t port)
+{
+ DECLARE_DOMCTL;
+
+ domctl.cmd = XEN_DOMCTL_subscribe;
+ domctl.domain = dom;
+ domctl.u.subscribe.port = port;
+
+ return do_domctl(xc_handle, &domctl);
+}
+
/*
* Local variables:
* mode: C
diff -r 9cf72db44ee9 -r 14fd83fe71c3 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h Fri Jul 04 11:54:21 2008 +0100
+++ b/tools/libxc/xenctrl.h Fri Jul 04 12:00:24 2008 +0100
@@ -810,6 +810,12 @@ int xc_acm_op(int xc_handle, int cmd, vo
int xc_flask_op(int xc_handle, flask_op_t *op);
+/*
+ * Subscribe to state changes in a domain via evtchn.
+ * Returns -1 on failure, in which case errno will be set appropriately.
+ */
+int xc_dom_subscribe(int xc_handle, domid_t domid, evtchn_port_t port);
+
/**************************
* GRANT TABLE OPERATIONS *
**************************/
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/arch/x86/traps.c Fri Jul 04 12:00:24 2008 +0100
@@ -61,6 +61,7 @@
#include <asm/msr.h>
#include <asm/shared.h>
#include <asm/x86_emulate.h>
+#include <asm/traps.h>
#include <asm/hvm/vpt.h>
#include <public/arch-x86/cpuid.h>
@@ -2678,25 +2679,51 @@ asmlinkage void do_general_protection(st
panic("GENERAL PROTECTION FAULT\n[error_code=%04x]\n", regs->error_code);
}
+static DEFINE_PER_CPU(struct softirq_trap, softirq_trap);
+
static void nmi_mce_softirq(void)
{
- /* Only used to defer wakeup of dom0,vcpu0 to a safe (non-NMI) context. */
- vcpu_kick(dom0->vcpu[0]);
+ int cpu = smp_processor_id();
+ struct softirq_trap *st = &per_cpu(softirq_trap, cpu);
+ cpumask_t affinity;
+
+ BUG_ON(st == NULL);
+ BUG_ON(st->vcpu == NULL);
+
+ /* Set the tmp value unconditionally, so that
+ * the check in the iret hypercall works. */
+ st->vcpu->cpu_affinity_tmp = st->vcpu->cpu_affinity;
+
+ if ((cpu != st->processor)
+ || (st->processor != st->vcpu->processor))
+ {
+ /* We are on a different physical cpu.
+ * Make sure to wakeup the vcpu on the
+ * specified processor.
+ */
+ cpus_clear(affinity);
+ cpu_set(st->processor, affinity);
+ vcpu_set_affinity(st->vcpu, &affinity);
+
+ /* Affinity is restored in the iret hypercall. */
+ }
+
+ /* Only used to defer wakeup of domain/vcpu to
+ * a safe (non-NMI/MCE) context.
+ */
+ vcpu_kick(st->vcpu);
}
static void nmi_dom0_report(unsigned int reason_idx)
{
- struct domain *d;
- struct vcpu *v;
-
- if ( ((d = dom0) == NULL) || ((v = d->vcpu[0]) == NULL) )
+ struct domain *d = dom0;
+
+ if ( (d == NULL) || (d->vcpu[0] == NULL) )
return;
set_bit(reason_idx, nmi_reason(d));
- /* Not safe to wake a vcpu here, or even to schedule a tasklet! */
- if ( !test_and_set_bool(v->nmi_pending) )
- raise_softirq(NMI_MCE_SOFTIRQ);
+ send_guest_trap(d, 0, TRAP_nmi);
}
asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
@@ -3010,6 +3037,35 @@ long unregister_guest_nmi_callback(void)
return 0;
}
+int send_guest_trap(struct domain *d, uint16_t vcpuid, unsigned int trap_nr)
+{
+ struct vcpu *v;
+ struct softirq_trap *st;
+
+ BUG_ON(d == NULL);
+ BUG_ON(vcpuid >= MAX_VIRT_CPUS);
+ v = d->vcpu[vcpuid];
+
+ switch (trap_nr) {
+ case TRAP_nmi:
+ if ( !test_and_set_bool(v->nmi_pending) ) {
+ st = &per_cpu(softirq_trap, smp_processor_id());
+ st->domain = dom0;
+ st->vcpu = dom0->vcpu[0];
+ st->processor = st->vcpu->processor;
+
+ /* not safe to wake up a vcpu here */
+ raise_softirq(NMI_MCE_SOFTIRQ);
+ return 0;
+ }
+ break;
+ }
+
+ /* delivery failed */
+ return -EIO;
+}
+
+
long do_set_trap_table(XEN_GUEST_HANDLE(const_trap_info_t) traps)
{
struct trap_info cur;
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/arch/x86/x86_32/traps.c
--- a/xen/arch/x86/x86_32/traps.c Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/arch/x86/x86_32/traps.c Fri Jul 04 12:00:24 2008 +0100
@@ -255,6 +255,10 @@ unsigned long do_iret(void)
goto exit_and_crash;
}
+ /* Restore affinity. */
+ if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
+ vcpu_set_affinity(v, &v->cpu_affinity_tmp);
+
/* No longer in NMI context. */
v->nmi_masked = 0;
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/arch/x86/x86_64/compat/traps.c
--- a/xen/arch/x86/x86_64/compat/traps.c Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/arch/x86/x86_64/compat/traps.c Fri Jul 04 12:00:24 2008 +0100
@@ -121,6 +121,10 @@ unsigned int compat_iret(void)
else
regs->_esp += 16;
+ /* Restore affinity. */
+ if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
+ vcpu_set_affinity(v, &v->cpu_affinity_tmp);
+
/* No longer in NMI context. */
v->nmi_masked = 0;
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/arch/x86/x86_64/traps.c
--- a/xen/arch/x86/x86_64/traps.c Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/arch/x86/x86_64/traps.c Fri Jul 04 12:00:24 2008 +0100
@@ -288,6 +288,10 @@ unsigned long do_iret(void)
regs->rcx = iret_saved.rcx;
}
+ /* Restore affinity. */
+ if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
+ vcpu_set_affinity(v, &v->cpu_affinity_tmp);
+
/* No longer in NMI context. */
v->nmi_masked = 0;
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/common/domain.c
--- a/xen/common/domain.c Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/common/domain.c Fri Jul 04 12:00:24 2008 +0100
@@ -97,7 +97,13 @@ static void __domain_finalise_shutdown(s
return;
d->is_shut_down = 1;
- send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+ if ( d->shutdown_code == SHUTDOWN_suspend
+ && d->suspend_evtchn > 0 )
+ {
+ evtchn_set_pending(dom0->vcpu[0], d->suspend_evtchn);
+ }
+ else
+ send_guest_global_virq(dom0, VIRQ_DOM_EXC);
}
static void vcpu_check_shutdown(struct vcpu *v)
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/common/domctl.c
--- a/xen/common/domctl.c Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/common/domctl.c Fri Jul 04 12:00:24 2008 +0100
@@ -824,6 +824,21 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
}
break;
+ case XEN_DOMCTL_subscribe:
+ {
+ struct domain *d;
+
+ ret = -ESRCH;
+ d = rcu_lock_domain_by_id(op->domain);
+ if ( d != NULL )
+ {
+ d->suspend_evtchn = op->u.subscribe.port;
+ rcu_unlock_domain(d);
+ ret = 0;
+ }
+ }
+ break;
+
default:
ret = arch_do_domctl(op, u_domctl);
break;
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/include/public/domctl.h
--- a/xen/include/public/domctl.h Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/include/public/domctl.h Fri Jul 04 12:00:24 2008 +0100
@@ -600,6 +600,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpuid
DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpuid_t);
#endif
+#define XEN_DOMCTL_subscribe 29
+struct xen_domctl_subscribe {
+ uint32_t port; /* IN */
+};
+typedef struct xen_domctl_subscribe xen_domctl_subscribe_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_subscribe_t);
+
struct xen_domctl {
uint32_t cmd;
uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
@@ -638,6 +645,7 @@ struct xen_domctl {
struct xen_domctl_ext_vcpucontext ext_vcpucontext;
struct xen_domctl_set_opt_feature set_opt_feature;
struct xen_domctl_set_target set_target;
+ struct xen_domctl_subscribe subscribe;
#if defined(__i386__) || defined(__x86_64__)
struct xen_domctl_cpuid cpuid;
#endif
diff -r 9cf72db44ee9 -r 14fd83fe71c3 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Fri Jul 04 11:54:21 2008 +0100
+++ b/xen/include/xen/sched.h Fri Jul 04 12:00:24 2008 +0100
@@ -130,6 +130,8 @@ struct vcpu
/* Bitmask of CPUs on which this VCPU may run. */
cpumask_t cpu_affinity;
+ /* Used to change affinity temporarily. */
+ cpumask_t cpu_affinity_tmp;
/* Bitmask of CPUs which are holding onto this VCPU's state. */
cpumask_t vcpu_dirty_cpumask;
@@ -208,6 +210,10 @@ struct domain
bool_t is_shutting_down; /* in process of shutting down? */
bool_t is_shut_down; /* fully shut down? */
int shutdown_code;
+
+ /* If this is not 0, send suspend notification here instead of
+ * raising DOM_EXC */
+ int suspend_evtchn;
atomic_t pause_count;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|