# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 8860eba3dcad1bba929d3703a9ee603c197a402a
# Parent 449dcaff25513813da8bcda94ffc85f3f14c5857
[XEN] Fix domctl for changing VCPU affinity.
Now works for any VCPU, including the caller's VCPU.
By not synchronously pausing the affected VCPU we avoid
any risk of deadlock.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/common/domctl.c | 43 ++++++++++++--------------------------
xen/common/sched_credit.c | 43 --------------------------------------
xen/common/sched_sedf.c | 15 -------------
xen/common/schedule.c | 50 ++++++++++++++++++++++++++++++++++++++++++++-
xen/include/xen/sched-if.h | 2 -
xen/include/xen/sched.h | 17 +++++++++++----
6 files changed, 76 insertions(+), 94 deletions(-)
diff -r 449dcaff2551 -r 8860eba3dcad xen/common/domctl.c
--- a/xen/common/domctl.c Thu Sep 21 18:29:48 2006 +0100
+++ b/xen/common/domctl.c Thu Sep 21 19:34:00 2006 +0100
@@ -356,37 +356,20 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
struct vcpu *v;
cpumask_t new_affinity;
+ ret = -ESRCH;
if ( d == NULL )
- {
- ret = -ESRCH;
- break;
- }
-
- if ( (op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS) ||
- !d->vcpu[op->u.vcpuaffinity.vcpu] )
- {
- ret = -EINVAL;
- put_domain(d);
- break;
- }
-
- v = d->vcpu[op->u.vcpuaffinity.vcpu];
- if ( v == NULL )
- {
- ret = -ESRCH;
- put_domain(d);
- break;
- }
+ break;
+
+ ret = -EINVAL;
+ if ( op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS )
+ goto vcpuaffinity_out;
+
+ ret = -ESRCH;
+ if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
+ goto vcpuaffinity_out;
if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
{
- if ( v == current )
- {
- ret = -EINVAL;
- put_domain(d);
- break;
- }
-
xenctl_cpumap_to_cpumask(
&new_affinity, &op->u.vcpuaffinity.cpumap);
ret = vcpu_set_affinity(v, &new_affinity);
@@ -395,8 +378,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
{
cpumask_to_xenctl_cpumap(
&op->u.vcpuaffinity.cpumap, &v->cpu_affinity);
- }
-
+ ret = 0;
+ }
+
+ vcpuaffinity_out:
put_domain(d);
}
break;
diff -r 449dcaff2551 -r 8860eba3dcad xen/common/sched_credit.c
--- a/xen/common/sched_credit.c Thu Sep 21 18:29:48 2006 +0100
+++ b/xen/common/sched_credit.c Thu Sep 21 19:34:00 2006 +0100
@@ -572,47 +572,6 @@ csched_vcpu_wake(struct vcpu *vc)
}
static int
-csched_vcpu_set_affinity(struct vcpu *vc, cpumask_t *affinity)
-{
- unsigned long flags;
- int lcpu;
-
- if ( vc == current )
- {
- /* No locking needed but also can't move on the spot... */
- if ( !cpu_isset(vc->processor, *affinity) )
- return -EBUSY;
-
- vc->cpu_affinity = *affinity;
- }
- else
- {
- /* Pause, modify, and unpause. */
- vcpu_pause(vc);
-
- vc->cpu_affinity = *affinity;
- if ( !cpu_isset(vc->processor, vc->cpu_affinity) )
- {
- /*
- * We must grab the scheduler lock for the CPU currently owning
- * this VCPU before changing its ownership.
- */
- vcpu_schedule_lock_irqsave(vc, flags);
- lcpu = vc->processor;
-
- vc->processor = first_cpu(vc->cpu_affinity);
-
- spin_unlock_irqrestore(&per_cpu(schedule_data, lcpu).schedule_lock,
- flags);
- }
-
- vcpu_unpause(vc);
- }
-
- return 0;
-}
-
-static int
csched_dom_cntl(
struct domain *d,
struct xen_domctl_scheduler_op *op)
@@ -1227,8 +1186,6 @@ struct scheduler sched_credit_def = {
.sleep = csched_vcpu_sleep,
.wake = csched_vcpu_wake,
- .set_affinity = csched_vcpu_set_affinity,
-
.adjust = csched_dom_cntl,
.tick = csched_tick,
diff -r 449dcaff2551 -r 8860eba3dcad xen/common/sched_sedf.c
--- a/xen/common/sched_sedf.c Thu Sep 21 18:29:48 2006 +0100
+++ b/xen/common/sched_sedf.c Thu Sep 21 19:34:00 2006 +0100
@@ -1175,20 +1175,6 @@ void sedf_wake(struct vcpu *d)
}
-static int sedf_set_affinity(struct vcpu *v, cpumask_t *affinity)
-{
- if ( v == current )
- return cpu_isset(v->processor, *affinity) ? 0 : -EBUSY;
-
- vcpu_pause(v);
- v->cpu_affinity = *affinity;
- v->processor = first_cpu(v->cpu_affinity);
- vcpu_unpause(v);
-
- return 0;
-}
-
-
/* Print a lot of useful information about a domains in the system */
static void sedf_dump_domain(struct vcpu *d)
{
@@ -1449,7 +1435,6 @@ struct scheduler sched_sedf_def = {
.sleep = sedf_sleep,
.wake = sedf_wake,
.adjust = sedf_adjust,
- .set_affinity = sedf_set_affinity
};
/*
diff -r 449dcaff2551 -r 8860eba3dcad xen/common/schedule.c
--- a/xen/common/schedule.c Thu Sep 21 18:29:48 2006 +0100
+++ b/xen/common/schedule.c Thu Sep 21 19:34:00 2006 +0100
@@ -181,15 +181,56 @@ void vcpu_wake(struct vcpu *v)
TRACE_2D(TRC_SCHED_WAKE, v->domain->domain_id, v->vcpu_id);
}
+static void vcpu_migrate(struct vcpu *v)
+{
+ cpumask_t online_affinity;
+ unsigned long flags;
+ int old_cpu;
+
+ vcpu_schedule_lock_irqsave(v, flags);
+
+ if ( test_bit(_VCPUF_running, &v->vcpu_flags) ||
+ !test_and_clear_bit(_VCPUF_migrating, &v->vcpu_flags) )
+ {
+ vcpu_schedule_unlock_irqrestore(v, flags);
+ return;
+ }
+
+ /* Switch to new CPU, then unlock old CPU. */
+ old_cpu = v->processor;
+ cpus_and(online_affinity, v->cpu_affinity, cpu_online_map);
+ v->processor = first_cpu(online_affinity);
+ spin_unlock_irqrestore(
+ &per_cpu(schedule_data, old_cpu).schedule_lock, flags);
+
+ /* Wake on new CPU. */
+ vcpu_wake(v);
+}
+
int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity)
{
cpumask_t online_affinity;
+ unsigned long flags;
cpus_and(online_affinity, *affinity, cpu_online_map);
if ( cpus_empty(online_affinity) )
return -EINVAL;
- return SCHED_OP(set_affinity, v, affinity);
+ vcpu_schedule_lock_irqsave(v, flags);
+
+ v->cpu_affinity = *affinity;
+ if ( !cpu_isset(v->processor, v->cpu_affinity) )
+ set_bit(_VCPUF_migrating, &v->vcpu_flags);
+
+ vcpu_schedule_unlock_irqrestore(v, flags);
+
+ if ( test_bit(_VCPUF_migrating, &v->vcpu_flags) )
+ {
+ vcpu_sleep_nosync(v);
+ vcpu_migrate(v);
+ }
+
+ return 0;
}
/* Block the currently-executing domain until a pertinent event occurs. */
@@ -555,6 +596,13 @@ static void __enter_scheduler(void)
context_switch(prev, next);
}
+void context_saved(struct vcpu *prev)
+{
+ clear_bit(_VCPUF_running, &prev->vcpu_flags);
+
+ if ( unlikely(test_bit(_VCPUF_migrating, &prev->vcpu_flags)) )
+ vcpu_migrate(prev);
+}
/****************************************************************************
* Timers: the scheduler utilises a number of timers
diff -r 449dcaff2551 -r 8860eba3dcad xen/include/xen/sched-if.h
--- a/xen/include/xen/sched-if.h Thu Sep 21 18:29:48 2006 +0100
+++ b/xen/include/xen/sched-if.h Thu Sep 21 19:34:00 2006 +0100
@@ -69,8 +69,6 @@ struct scheduler {
void (*sleep) (struct vcpu *);
void (*wake) (struct vcpu *);
- int (*set_affinity) (struct vcpu *, cpumask_t *);
-
struct task_slice (*do_schedule) (s_time_t);
int (*adjust) (struct domain *,
diff -r 449dcaff2551 -r 8860eba3dcad xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Thu Sep 21 18:29:48 2006 +0100
+++ b/xen/include/xen/sched.h Thu Sep 21 19:34:00 2006 +0100
@@ -312,7 +312,7 @@ extern void context_switch(
* saved to memory. Alternatively, if implementing lazy context switching,
* ensure that invoking sync_vcpu_execstate() will switch and commit @prev.
*/
-#define context_saved(prev) (clear_bit(_VCPUF_running, &(prev)->vcpu_flags))
+extern void context_saved(struct vcpu *prev);
/* Called by the scheduler to continue running the current VCPU. */
extern void continue_running(
@@ -386,9 +386,12 @@ extern struct domain *domain_list;
/* VCPU is paused by the hypervisor? */
#define _VCPUF_paused 11
#define VCPUF_paused (1UL<<_VCPUF_paused)
-/* VCPU is blocked awaiting an event to be consumed by Xen. */
+ /* VCPU is blocked awaiting an event to be consumed by Xen. */
#define _VCPUF_blocked_in_xen 12
#define VCPUF_blocked_in_xen (1UL<<_VCPUF_blocked_in_xen)
+ /* VCPU affinity has changed: migrating to a new CPU. */
+#define _VCPUF_migrating 13
+#define VCPUF_migrating (1UL<<_VCPUF_migrating)
/*
* Per-domain flags (domain_flags).
@@ -418,9 +421,15 @@ static inline int vcpu_runnable(struct v
static inline int vcpu_runnable(struct vcpu *v)
{
return ( !(v->vcpu_flags &
- (VCPUF_blocked|VCPUF_down|VCPUF_paused|VCPUF_blocked_in_xen)) &&
+ ( VCPUF_blocked |
+ VCPUF_down |
+ VCPUF_paused |
+ VCPUF_blocked_in_xen |
+ VCPUF_migrating )) &&
!(v->domain->domain_flags &
- (DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) );
+ ( DOMF_shutdown |
+ DOMF_ctrl_pause |
+ DOMF_paused )));
}
void vcpu_pause(struct vcpu *v);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|