[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:
kfraser@localhost.localdomain committed 2006-09-21 19:34:00 +01:00
1 parent fc99b58762
commit 97bfffea3c
6 files changed
+72 -90

No files matched your search

+10 -25
View File
@@ -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;
-43
View File
@@ -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,
-15
View File
@@ -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
View File
@@ -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
-2
View File
@@ -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
View File
@@ -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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.