mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[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@xensource.com>
This commit is contained in:
1 parent
fc99b58762
commit
97bfffea3c
6 files changed
+72
-90
No files matched your search
+10
-25
@@ -356,37 +356,20 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
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;
|
||||
}
|
||||
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_domctl_t) u_domctl)
|
||||
{
|
||||
cpumask_to_xenctl_cpumap(
|
||||
&op->u.vcpuaffinity.cpumap, &v->cpu_affinity);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
vcpuaffinity_out:
|
||||
put_domain(d);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -571,47 +571,6 @@ csched_vcpu_wake(struct vcpu *vc)
|
||||
__runq_tickle(cpu, svc);
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+49
-1
@@ -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
|
||||
|
||||
@@ -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 *,
|
||||
|
||||
+13
-4
@@ -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 @@ extern struct domain *domain_list;
|
||||
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);
|
||||
|
||||