aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2012-01-28 13:48:03 +0000
committerDaniel De Graaf <dgdegra@tycho.nsa.gov>2012-01-28 13:48:03 +0000
commit87521589aa6a677bad2b4a80b8fd3ad152c1c274 (patch)
tree86d58beaeede99086666d61c3d1aff63ee800ee5 /xen/common
parent14eb3b41d03f75b89928fad8f720f7d49598b0be (diff)
downloadxen-87521589aa6a677bad2b4a80b8fd3ad152c1c274.tar.gz
xen-87521589aa6a677bad2b4a80b8fd3ad152c1c274.tar.bz2
xen-87521589aa6a677bad2b4a80b8fd3ad152c1c274.zip
xen: allow global VIRQ handlers to be delegated to other domains
This patch sends global VIRQs to a domain designated as the VIRQ handler instead of sending all global VIRQ events to dom0. This is required in order to run xenstored in a stubdom, because VIRQ_DOM_EXC must be sent to xenstored for domain destruction to work properly. This patch was inspired by the xenstored stubdomain patch series sent to xen-devel by Alex Zeffertt in 2009. Signed-off-by: Diego Ongaro <diego.ongaro@citrix.com> Signed-off-by: Alex Zeffertt <alex.zeffertt@eu.citrix.com> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/common')
-rw-r--r--xen/common/cpu.c4
-rw-r--r--xen/common/domain.c8
-rw-r--r--xen/common/domctl.c17
-rw-r--r--xen/common/event_channel.c66
-rw-r--r--xen/common/trace.c2
5 files changed, 89 insertions, 8 deletions
diff --git a/xen/common/cpu.c b/xen/common/cpu.c
index 79abdb7b09..630881e5ab 100644
--- a/xen/common/cpu.c
+++ b/xen/common/cpu.c
@@ -108,7 +108,7 @@ int cpu_down(unsigned int cpu)
notifier_rc = notifier_call_chain(&cpu_chain, CPU_DEAD, hcpu, NULL);
BUG_ON(notifier_rc != NOTIFY_DONE);
- send_guest_global_virq(dom0, VIRQ_PCPU_STATE);
+ send_global_virq(VIRQ_PCPU_STATE);
cpu_hotplug_done();
return 0;
@@ -148,7 +148,7 @@ int cpu_up(unsigned int cpu)
notifier_rc = notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu, NULL);
BUG_ON(notifier_rc != NOTIFY_DONE);
- send_guest_global_virq(dom0, VIRQ_PCPU_STATE);
+ send_global_virq(VIRQ_PCPU_STATE);
cpu_hotplug_done();
return 0;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index fd202100ef..500c7a210c 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -86,7 +86,7 @@ static void __domain_finalise_shutdown(struct domain *d)
if ( (d->shutdown_code == SHUTDOWN_suspend) && d->suspend_evtchn )
evtchn_send(d, d->suspend_evtchn);
else
- send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+ send_global_virq(VIRQ_DOM_EXC);
}
static void vcpu_check_shutdown(struct vcpu *v)
@@ -480,7 +480,7 @@ int domain_kill(struct domain *d)
}
d->is_dying = DOMDYING_dead;
put_domain(d);
- send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+ send_global_virq(VIRQ_DOM_EXC);
/* fallthrough */
case DOMDYING_dead:
break;
@@ -621,7 +621,7 @@ void domain_pause_for_debugger(void)
for_each_vcpu ( d, v )
vcpu_sleep_nosync(v);
- send_guest_global_virq(dom0, VIRQ_DEBUGGER);
+ send_global_virq(VIRQ_DEBUGGER);
}
/* Complete domain destroy after RCU readers are not holding old references. */
@@ -680,7 +680,7 @@ static void complete_domain_destroy(struct rcu_head *head)
free_cpumask_var(d->domain_dirty_cpumask);
free_domain_struct(d);
- send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+ send_global_virq(VIRQ_DOM_EXC);
}
/* Release resources belonging to task @p. */
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 5b0fc4a511..8001a916cc 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -995,6 +995,23 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
}
break;
+ case XEN_DOMCTL_set_virq_handler:
+ {
+ struct domain *d;
+ uint32_t virq = op->u.set_virq_handler.virq;
+
+ ret = -ESRCH;
+ d = rcu_lock_domain_by_id(op->domain);
+ if ( d != NULL )
+ {
+ ret = xsm_set_virq_handler(d, virq);
+ if ( !ret )
+ ret = set_global_virq_handler(d, virq);
+ rcu_unlock_domain(d);
+ }
+ }
+ break;
+
default:
ret = arch_do_domctl(op, u_domctl);
break;
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 921204237d..43bd16755e 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -689,7 +689,7 @@ void send_guest_vcpu_virq(struct vcpu *v, int virq)
spin_unlock_irqrestore(&v->virq_lock, flags);
}
-void send_guest_global_virq(struct domain *d, int virq)
+static void send_guest_global_virq(struct domain *d, int virq)
{
unsigned long flags;
int port;
@@ -739,6 +739,68 @@ int send_guest_pirq(struct domain *d, const struct pirq *pirq)
return evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
}
+static struct domain *global_virq_handlers[NR_VIRQS] __read_mostly;
+
+static DEFINE_SPINLOCK(global_virq_handlers_lock);
+
+void send_global_virq(uint32_t virq)
+{
+ ASSERT(virq < NR_VIRQS);
+ ASSERT(virq_is_global(virq));
+
+ send_guest_global_virq(global_virq_handlers[virq] ?: dom0, virq);
+}
+
+int set_global_virq_handler(struct domain *d, uint32_t virq)
+{
+ struct domain *old;
+
+ if (virq >= NR_VIRQS)
+ return -EINVAL;
+ if (!virq_is_global(virq))
+ return -EINVAL;
+
+ if (global_virq_handlers[virq] == d)
+ return 0;
+
+ if (unlikely(!get_domain(d)))
+ return -EINVAL;
+
+ spin_lock(&global_virq_handlers_lock);
+ old = global_virq_handlers[virq];
+ global_virq_handlers[virq] = d;
+ spin_unlock(&global_virq_handlers_lock);
+
+ if (old != NULL)
+ put_domain(old);
+
+ return 0;
+}
+
+static void clear_global_virq_handlers(struct domain *d)
+{
+ uint32_t virq;
+ int put_count = 0;
+
+ spin_lock(&global_virq_handlers_lock);
+
+ for (virq = 0; virq < NR_VIRQS; virq++)
+ {
+ if (global_virq_handlers[virq] == d)
+ {
+ global_virq_handlers[virq] = NULL;
+ put_count++;
+ }
+ }
+
+ spin_unlock(&global_virq_handlers_lock);
+
+ while (put_count)
+ {
+ put_domain(d);
+ put_count--;
+ }
+}
static long evtchn_status(evtchn_status_t *status)
{
@@ -1160,6 +1222,8 @@ void evtchn_destroy(struct domain *d)
d->evtchn[i] = NULL;
}
spin_unlock(&d->event_lock);
+
+ clear_global_virq_handlers(d);
}
diff --git a/xen/common/trace.c b/xen/common/trace.c
index 5772f248f7..58cbf39be9 100644
--- a/xen/common/trace.c
+++ b/xen/common/trace.c
@@ -661,7 +661,7 @@ static inline void insert_lost_records(struct t_buf *buf)
*/
static void trace_notify_dom0(unsigned long unused)
{
- send_guest_global_virq(dom0, VIRQ_TBUF);
+ send_global_virq(VIRQ_TBUF);
}
static DECLARE_SOFTIRQ_TASKLET(trace_notify_dom0_tasklet,
trace_notify_dom0, 0);