mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
cpupools [1/6]: hypervisor changes
Signed-off-by: Juergen Gross <juergen.gross@ts.fujitsu.com>
This commit is contained in:
1 parent
b066d6894d
commit
78be3dbbfe
14 files changed
+1565
-375
No files matched your search
@@ -9,6 +9,7 @@
|
||||
#include <xen/lib.h>
|
||||
#include <xen/ctype.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/sched-if.h>
|
||||
#include <xen/smp.h>
|
||||
#include <xen/delay.h>
|
||||
#include <xen/event.h>
|
||||
@@ -84,7 +85,7 @@ integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
|
||||
struct vcpu *__init alloc_dom0_vcpu0(void)
|
||||
{
|
||||
if ( opt_dom0_max_vcpus == 0 )
|
||||
opt_dom0_max_vcpus = num_online_cpus();
|
||||
opt_dom0_max_vcpus = num_cpupool_cpus(cpupool0);
|
||||
if ( opt_dom0_max_vcpus > MAX_VIRT_CPUS )
|
||||
opt_dom0_max_vcpus = MAX_VIRT_CPUS;
|
||||
|
||||
@@ -277,7 +278,7 @@ int __init construct_dom0(
|
||||
unsigned long _initrd_start, unsigned long initrd_len,
|
||||
char *cmdline)
|
||||
{
|
||||
int i, rc, compatible, compat32, order, machine;
|
||||
int i, cpu, rc, compatible, compat32, order, machine;
|
||||
struct cpu_user_regs *regs;
|
||||
unsigned long pfn, mfn;
|
||||
unsigned long nr_pages;
|
||||
@@ -776,8 +777,12 @@ int __init construct_dom0(
|
||||
|
||||
printk("Dom0 has maximum %u VCPUs\n", opt_dom0_max_vcpus);
|
||||
|
||||
cpu = first_cpu(cpupool0->cpu_valid);
|
||||
for ( i = 1; i < opt_dom0_max_vcpus; i++ )
|
||||
(void)alloc_vcpu(d, i, i % num_online_cpus());
|
||||
{
|
||||
cpu = cycle_cpu(cpu, cpupool0->cpu_valid);
|
||||
(void)alloc_vcpu(d, i, cpu);
|
||||
}
|
||||
|
||||
/* Set up CR3 value for write_ptbase */
|
||||
if ( paging_mode_enabled(d) )
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <xen/init.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/sched-if.h>
|
||||
#include <xen/domain.h>
|
||||
#include <xen/serial.h>
|
||||
#include <xen/softirq.h>
|
||||
@@ -1093,6 +1094,11 @@ void __init __start_xen(unsigned long mbi_p)
|
||||
if ( !tboot_protect_mem_regions() )
|
||||
panic("Could not protect TXT memory regions\n");
|
||||
|
||||
/* Create initial cpupool 0. */
|
||||
cpupool0 = cpupool_create(0, NULL);
|
||||
if ( (cpupool0 == NULL) || cpupool0_cpu_assign(cpupool0) )
|
||||
panic("Error creating cpupool 0\n");
|
||||
|
||||
/* Create initial domain 0. */
|
||||
dom0 = domain_create(0, DOMCRF_s3_integrity, DOM0_SSIDREF);
|
||||
if ( (dom0 == NULL) || (alloc_dom0_vcpu0() == NULL) )
|
||||
|
||||
+11
-7
@@ -39,6 +39,7 @@
|
||||
#include <xen/mm.h>
|
||||
#include <xen/domain.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/sched-if.h>
|
||||
#include <xen/irq.h>
|
||||
#include <xen/delay.h>
|
||||
#include <xen/softirq.h>
|
||||
@@ -1296,10 +1297,11 @@ int __cpu_disable(void)
|
||||
remove_siblinginfo(cpu);
|
||||
|
||||
/* It's now safe to remove this processor from the online map */
|
||||
cpu_clear(cpu, cpupool0->cpu_valid);
|
||||
cpu_clear(cpu, cpu_online_map);
|
||||
fixup_irqs();
|
||||
|
||||
cpu_disable_scheduler();
|
||||
cpu_disable_scheduler(cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1336,11 +1338,6 @@ int cpu_down(unsigned int cpu)
|
||||
if (!spin_trylock(&cpu_add_remove_lock))
|
||||
return -EBUSY;
|
||||
|
||||
if (num_online_cpus() == 1) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Can not offline BSP */
|
||||
if (cpu == 0) {
|
||||
err = -EINVAL;
|
||||
@@ -1352,13 +1349,19 @@ int cpu_down(unsigned int cpu)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = cpupool_cpu_remove(cpu);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
printk("Prepare to bring CPU%d down...\n", cpu);
|
||||
|
||||
cpufreq_del_cpu(cpu);
|
||||
|
||||
err = stop_machine_run(take_cpu_down, NULL, cpu);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
cpupool_cpu_add(cpu);
|
||||
goto out;
|
||||
}
|
||||
|
||||
__cpu_die(cpu);
|
||||
|
||||
@@ -1559,6 +1562,7 @@ int __devinit __cpu_up(unsigned int cpu)
|
||||
process_pending_softirqs();
|
||||
}
|
||||
|
||||
cpupool_cpu_add(cpu);
|
||||
cpufreq_add_cpu(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
obj-y += bitmap.o
|
||||
obj-y += cpu.o
|
||||
obj-y += cpupool.o
|
||||
obj-y += domctl.o
|
||||
obj-y += domain.o
|
||||
obj-y += event_channel.o
|
||||
|
||||
@@ -0,0 +1,604 @@
|
||||
/******************************************************************************
|
||||
* cpupool.c
|
||||
*
|
||||
* Generic cpupool-handling functions.
|
||||
*
|
||||
* Cpupools are a feature to have configurable scheduling domains. Each
|
||||
* cpupool runs an own scheduler on a dedicated set of physical cpus.
|
||||
* A domain is bound to one cpupool at any time, but it can be moved to
|
||||
* another cpupool.
|
||||
*
|
||||
* (C) 2009, Juergen Gross, Fujitsu Technology Solutions
|
||||
*/
|
||||
|
||||
#include <xen/lib.h>
|
||||
#include <xen/init.h>
|
||||
#include <xen/cpumask.h>
|
||||
#include <xen/percpu.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/sched-if.h>
|
||||
|
||||
#define for_each_cpupool(ptr) \
|
||||
for ((ptr) = &cpupool_list; *(ptr) != NULL; (ptr) = &((*(ptr))->next))
|
||||
|
||||
struct cpupool *cpupool0; /* Initial cpupool with Dom0 */
|
||||
cpumask_t cpupool_free_cpus; /* cpus not in any cpupool */
|
||||
|
||||
static struct cpupool *cpupool_list; /* linked list, sorted by poolid */
|
||||
|
||||
static int cpupool0_max_cpus;
|
||||
integer_param("pool0_max_cpus", cpupool0_max_cpus);
|
||||
|
||||
static int cpupool_moving_cpu = -1;
|
||||
static struct cpupool *cpupool_cpu_moving = NULL;
|
||||
static cpumask_t cpupool_locked_cpus = CPU_MASK_NONE;
|
||||
|
||||
/* cpupool lock: be carefull, this lock is sometimes released on another cpu
|
||||
* as it was obtained!
|
||||
*/
|
||||
static DEFINE_SPINLOCK(cpupool_lock);
|
||||
|
||||
DEFINE_PER_CPU(struct cpupool *, cpupool);
|
||||
|
||||
static struct cpupool *alloc_cpupool_struct(void)
|
||||
{
|
||||
return xmalloc(struct cpupool);
|
||||
}
|
||||
|
||||
static void free_cpupool_struct(struct cpupool *c)
|
||||
{
|
||||
xfree(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* find a cpupool by it's id. to be called with cpupool lock held
|
||||
* if exact is not specified, the first cpupool with an id larger or equal to
|
||||
* the searched id is returned
|
||||
* returns NULL if not found.
|
||||
*/
|
||||
static struct cpupool *cpupool_find_by_id(int id, int exact)
|
||||
{
|
||||
struct cpupool **q;
|
||||
|
||||
for_each_cpupool(q)
|
||||
{
|
||||
if ( (*q)->cpupool_id == id )
|
||||
return *q;
|
||||
if ( (*q)->cpupool_id > id )
|
||||
break;
|
||||
}
|
||||
return exact ? NULL : *q;
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new cpupool with specified poolid and scheduler
|
||||
* returns pointer to new cpupool structure if okay, NULL else
|
||||
* possible failures:
|
||||
* - no memory
|
||||
* - poolid already used
|
||||
* - unknown scheduler
|
||||
*/
|
||||
struct cpupool *cpupool_create(int poolid, char *sched)
|
||||
{
|
||||
struct cpupool *c;
|
||||
struct cpupool **q;
|
||||
int last = 0;
|
||||
|
||||
if ( (c = alloc_cpupool_struct()) == NULL )
|
||||
return NULL;
|
||||
memset(c, 0, sizeof(*c));
|
||||
|
||||
printk(XENLOG_DEBUG "cpupool_create(pool=%d,sched=%s)\n", poolid, sched);
|
||||
spin_lock(&cpupool_lock);
|
||||
for_each_cpupool(q)
|
||||
{
|
||||
last = (*q)->cpupool_id;
|
||||
if ( (poolid != CPUPOOLID_NONE) && (last >= poolid) )
|
||||
break;
|
||||
}
|
||||
if ( *q != NULL )
|
||||
{
|
||||
if ( (*q)->cpupool_id == poolid )
|
||||
{
|
||||
spin_unlock(&cpupool_lock);
|
||||
free_cpupool_struct(c);
|
||||
return NULL;
|
||||
}
|
||||
c->next = *q;
|
||||
}
|
||||
*q = c;
|
||||
c->cpupool_id = (poolid == CPUPOOLID_NONE) ? (last + 1) : poolid;
|
||||
if ( schedule_init_global(sched, &(c->sched)) )
|
||||
{
|
||||
spin_unlock(&cpupool_lock);
|
||||
cpupool_destroy(c);
|
||||
return NULL;
|
||||
}
|
||||
spin_unlock(&cpupool_lock);
|
||||
|
||||
printk("Created cpupool %d with scheduler %s (%s)\n", c->cpupool_id,
|
||||
c->sched.name, c->sched.opt_name);
|
||||
|
||||
return c;
|
||||
}
|
||||
/*
|
||||
* destroys the given cpupool
|
||||
* returns 0 on success, 1 else
|
||||
* possible failures:
|
||||
* - pool still in use
|
||||
* - cpus still assigned to pool
|
||||
* - pool not in list
|
||||
*/
|
||||
int cpupool_destroy(struct cpupool *c)
|
||||
{
|
||||
struct cpupool **q;
|
||||
|
||||
spin_lock(&cpupool_lock);
|
||||
for_each_cpupool(q)
|
||||
if ( *q == c )
|
||||
break;
|
||||
if ( (*q != c) || (c->n_dom != 0) || cpus_weight(c->cpu_valid) )
|
||||
{
|
||||
spin_unlock(&cpupool_lock);
|
||||
return 1;
|
||||
}
|
||||
*q = c->next;
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool_destroy(pool=%d)\n", c->cpupool_id);
|
||||
schedule_deinit_global(&(c->sched));
|
||||
free_cpupool_struct(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* assign a specific cpu to a cpupool
|
||||
* cpupool_lock must be held
|
||||
*/
|
||||
static int cpupool_assign_cpu_locked(struct cpupool *c, unsigned int cpu)
|
||||
{
|
||||
if ( (cpupool_moving_cpu == cpu) && (c != cpupool_cpu_moving) )
|
||||
return -EBUSY;
|
||||
per_cpu(cpupool, cpu) = c;
|
||||
schedule_cpu_switch(cpu, c);
|
||||
cpu_clear(cpu, cpupool_free_cpus);
|
||||
if (cpupool_moving_cpu == cpu)
|
||||
{
|
||||
cpupool_moving_cpu = -1;
|
||||
cpupool_cpu_moving = NULL;
|
||||
}
|
||||
cpu_set(cpu, c->cpu_valid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* assign free physical cpus to a cpupool
|
||||
* cpus assigned are unused cpus with lowest possible ids
|
||||
* returns the number of cpus assigned
|
||||
*/
|
||||
int cpupool_assign_ncpu(struct cpupool *c, int ncpu)
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
spin_lock(&cpupool_lock);
|
||||
for_each_cpu_mask(i, cpupool_free_cpus)
|
||||
{
|
||||
if ( cpupool_assign_cpu_locked(c, i) == 0 )
|
||||
n++;
|
||||
if ( n == ncpu )
|
||||
break;
|
||||
}
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool_assign_ncpu(pool=%d,ncpu=%d) rc %d\n",
|
||||
c->cpupool_id, ncpu, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
static long cpupool_unassign_cpu_helper(void *info)
|
||||
{
|
||||
struct cpupool *c = (struct cpupool *)info;
|
||||
int cpu = cpupool_moving_cpu;
|
||||
long ret;
|
||||
int cpupool_id = c->cpupool_id;
|
||||
|
||||
ret = cpu_disable_scheduler(cpu);
|
||||
cpu_set(cpu, cpupool_free_cpus);
|
||||
if ( !ret )
|
||||
{
|
||||
schedule_cpu_switch(cpu, NULL);
|
||||
per_cpu(cpupool, cpu) = NULL;
|
||||
cpupool_moving_cpu = -1;
|
||||
cpupool_cpu_moving = NULL;
|
||||
}
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool_unassign_cpu(pool=%d,cpu=%d) ret %ld\n",
|
||||
cpupool_id, cpu, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* unassign a specific cpu from a cpupool
|
||||
* we must be sure not to run on the cpu to be unassigned! to achieve this
|
||||
* the main functionality is performed via continue_hypercall_on_cpu on a
|
||||
* specific cpu.
|
||||
* if the cpu to be removed is the last one of the cpupool no active domain
|
||||
* must be bound to the cpupool. dying domains are moved to cpupool0 as they
|
||||
* might be zombies.
|
||||
* possible failures:
|
||||
* - last cpu and still active domains in cpupool
|
||||
* - cpu just being unplugged
|
||||
*/
|
||||
int cpupool_unassign_cpu(struct cpupool *c, unsigned int cpu)
|
||||
{
|
||||
int work_cpu;
|
||||
int ret;
|
||||
struct domain *d;
|
||||
int cpupool_id = c->cpupool_id;
|
||||
|
||||
printk(XENLOG_DEBUG "cpupool_unassign_cpu(pool=%d,cpu=%d)\n",
|
||||
cpupool_id, cpu);
|
||||
spin_lock(&cpupool_lock);
|
||||
ret = -EBUSY;
|
||||
if ( (cpupool_moving_cpu != -1) && (cpu != cpupool_moving_cpu) )
|
||||
goto out;
|
||||
if ( cpu_isset(cpu, cpupool_locked_cpus) )
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
if ( !cpu_isset(cpu, c->cpu_valid) && (cpu != cpupool_moving_cpu) )
|
||||
goto out;
|
||||
|
||||
if ( (c->n_dom > 0) && (cpus_weight(c->cpu_valid) == 1) &&
|
||||
(cpu != cpupool_moving_cpu) )
|
||||
{
|
||||
for_each_domain(d)
|
||||
{
|
||||
if ( d->cpupool != c )
|
||||
continue;
|
||||
if ( !d->is_dying )
|
||||
{
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
c->n_dom--;
|
||||
ret = sched_move_domain(d, cpupool0);
|
||||
if ( ret )
|
||||
{
|
||||
c->n_dom++;
|
||||
break;
|
||||
}
|
||||
cpupool0->n_dom++;
|
||||
}
|
||||
if ( ret )
|
||||
goto out;
|
||||
}
|
||||
cpupool_moving_cpu = cpu;
|
||||
cpupool_cpu_moving = c;
|
||||
cpu_clear(cpu, c->cpu_valid);
|
||||
work_cpu = smp_processor_id();
|
||||
if ( work_cpu == cpu )
|
||||
{
|
||||
work_cpu = first_cpu(cpupool0->cpu_valid);
|
||||
if ( work_cpu == cpu )
|
||||
work_cpu = next_cpu(cpu, cpupool0->cpu_valid);
|
||||
}
|
||||
return continue_hypercall_on_cpu(work_cpu, cpupool_unassign_cpu_helper, c);
|
||||
|
||||
out:
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool_unassign_cpu(pool=%d,cpu=%d) ret %d\n",
|
||||
cpupool_id, cpu, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* assign cpus to the default cpupool
|
||||
* default are all cpus, less cpus may be specified as boot parameter
|
||||
* possible failures:
|
||||
* - no cpu assigned
|
||||
*/
|
||||
int __init cpupool0_cpu_assign(struct cpupool *c)
|
||||
{
|
||||
if ( (cpupool0_max_cpus == 0) || (cpupool0_max_cpus > num_online_cpus()) )
|
||||
cpupool0_max_cpus = num_online_cpus();
|
||||
if ( !cpupool_assign_ncpu(cpupool0, cpupool0_max_cpus) )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* add a new domain to a cpupool
|
||||
* possible failures:
|
||||
* - pool does not exist
|
||||
* - no cpu assigned to pool
|
||||
*/
|
||||
int cpupool_add_domain(struct domain *d, int poolid)
|
||||
{
|
||||
struct cpupool *c;
|
||||
int rc = 1;
|
||||
int n_dom;
|
||||
|
||||
if ( poolid == CPUPOOLID_NONE )
|
||||
return 0;
|
||||
spin_lock(&cpupool_lock);
|
||||
c = cpupool_find_by_id(poolid, 1);
|
||||
if ( (c != NULL) && cpus_weight(c->cpu_valid) )
|
||||
{
|
||||
c->n_dom++;
|
||||
n_dom = c->n_dom;
|
||||
d->cpupool = c;
|
||||
rc = 0;
|
||||
}
|
||||
spin_unlock(&cpupool_lock);
|
||||
if (!rc)
|
||||
printk(XENLOG_DEBUG "cpupool_add_domain(dom=%d,pool=%d) n_dom %d\n",
|
||||
d->domain_id, poolid, n_dom);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove a domain from a cpupool
|
||||
*/
|
||||
void cpupool_rm_domain(struct domain *d)
|
||||
{
|
||||
int cpupool_id;
|
||||
int n_dom;
|
||||
|
||||
if ( d->cpupool == NULL )
|
||||
return;
|
||||
spin_lock(&cpupool_lock);
|
||||
cpupool_id = d->cpupool->cpupool_id;
|
||||
d->cpupool->n_dom--;
|
||||
n_dom = d->cpupool->n_dom;
|
||||
d->cpupool = NULL;
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool_rm_domain(dom=%d,pool=%d) n_dom %d\n",
|
||||
d->domain_id, cpupool_id, n_dom);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* called to add a new cpu to pool admin
|
||||
* we add a hotplugged cpu to the cpupool0 to be able to add it to dom0
|
||||
*/
|
||||
void cpupool_cpu_add(unsigned int cpu)
|
||||
{
|
||||
if ( cpupool0 == NULL )
|
||||
return;
|
||||
spin_lock(&cpupool_lock);
|
||||
cpu_clear(cpu, cpupool_locked_cpus);
|
||||
cpu_set(cpu, cpupool_free_cpus);
|
||||
cpupool_assign_cpu_locked(cpupool0, cpu);
|
||||
spin_unlock(&cpupool_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* called to remove a cpu from pool admin
|
||||
* the cpu to be removed is locked to avoid removing it from dom0
|
||||
* returns failure if not in pool0
|
||||
*/
|
||||
int cpupool_cpu_remove(unsigned int cpu)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&cpupool_lock);
|
||||
if ( !cpu_isset(cpu, cpupool0->cpu_valid))
|
||||
ret = -EBUSY;
|
||||
else
|
||||
cpu_set(cpu, cpupool_locked_cpus);
|
||||
spin_unlock(&cpupool_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* do cpupool related domctl operations
|
||||
*/
|
||||
int cpupool_do_domctl(struct xen_domctl_cpupool_op *op)
|
||||
{
|
||||
int ret;
|
||||
struct cpupool *c;
|
||||
|
||||
switch ( op->op )
|
||||
{
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_CREATE:
|
||||
{
|
||||
int poolid;
|
||||
const struct scheduler *sched;
|
||||
|
||||
poolid = (op->cpupool_id == XEN_DOMCTL_CPUPOOL_PAR_ANY) ?
|
||||
CPUPOOLID_NONE: op->cpupool_id;
|
||||
sched = scheduler_get_by_id(op->sched_id);
|
||||
ret = -ENOENT;
|
||||
if ( sched == NULL )
|
||||
break;
|
||||
ret = 0;
|
||||
c = cpupool_create(poolid, sched->opt_name);
|
||||
if ( c == NULL )
|
||||
ret = -EINVAL;
|
||||
else
|
||||
op->cpupool_id = c->cpupool_id;
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_DESTROY:
|
||||
{
|
||||
spin_lock(&cpupool_lock);
|
||||
c = cpupool_find_by_id(op->cpupool_id, 1);
|
||||
spin_unlock(&cpupool_lock);
|
||||
ret = -ENOENT;
|
||||
if ( c == NULL )
|
||||
break;
|
||||
ret = (cpupool_destroy(c) != 0) ? -EBUSY : 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_INFO:
|
||||
{
|
||||
spin_lock(&cpupool_lock);
|
||||
c = cpupool_find_by_id(op->cpupool_id, 0);
|
||||
spin_unlock(&cpupool_lock);
|
||||
ret = -ENOENT;
|
||||
if ( c == NULL )
|
||||
break;
|
||||
op->cpupool_id = c->cpupool_id;
|
||||
op->sched_id = c->sched.sched_id;
|
||||
op->n_dom = c->n_dom;
|
||||
cpumask_to_xenctl_cpumap(&(op->cpumap), &(c->cpu_valid));
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_ADDCPU:
|
||||
{
|
||||
unsigned cpu;
|
||||
|
||||
cpu = op->cpu;
|
||||
printk(XENLOG_DEBUG "cpupool_assign_cpu(pool=%d,cpu=%d)\n",
|
||||
op->cpupool_id, cpu);
|
||||
spin_lock(&cpupool_lock);
|
||||
if ( cpu == XEN_DOMCTL_CPUPOOL_PAR_ANY )
|
||||
cpu = first_cpu(cpupool_free_cpus);
|
||||
ret = -EINVAL;
|
||||
if ( cpu >= NR_CPUS )
|
||||
goto addcpu_out;
|
||||
ret = -EBUSY;
|
||||
if ( !cpu_isset(cpu, cpupool_free_cpus) )
|
||||
goto addcpu_out;
|
||||
c = cpupool_find_by_id(op->cpupool_id, 0);
|
||||
ret = -ENOENT;
|
||||
if ( c == NULL )
|
||||
goto addcpu_out;
|
||||
ret = cpupool_assign_cpu_locked(c, cpu);
|
||||
addcpu_out:
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool_assign_cpu(pool=%d,cpu=%d) ret %d\n",
|
||||
op->cpupool_id, cpu, ret);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_RMCPU:
|
||||
{
|
||||
unsigned cpu;
|
||||
|
||||
spin_lock(&cpupool_lock);
|
||||
c = cpupool_find_by_id(op->cpupool_id, 0);
|
||||
spin_unlock(&cpupool_lock);
|
||||
ret = -ENOENT;
|
||||
if ( c == NULL )
|
||||
break;
|
||||
cpu = op->cpu;
|
||||
if ( cpu == XEN_DOMCTL_CPUPOOL_PAR_ANY )
|
||||
cpu = last_cpu(c->cpu_valid);
|
||||
ret = -EINVAL;
|
||||
if ( cpu >= NR_CPUS )
|
||||
break;
|
||||
/* caution: cpupool_unassign_cpu uses continue_hypercall_on_cpu and
|
||||
* will continue after the local return
|
||||
*/
|
||||
ret = cpupool_unassign_cpu(c, cpu);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_MOVEDOMAIN:
|
||||
{
|
||||
struct domain *d;
|
||||
|
||||
ret = -EINVAL;
|
||||
if ( op->domid == 0 )
|
||||
break;
|
||||
ret = -ESRCH;
|
||||
d = rcu_lock_domain_by_id(op->domid);
|
||||
if ( d == NULL )
|
||||
break;
|
||||
if ( d->cpupool == NULL )
|
||||
{
|
||||
ret = -EINVAL;
|
||||
rcu_unlock_domain(d);
|
||||
break;
|
||||
}
|
||||
printk(XENLOG_DEBUG "cpupool move_domain(dom=%d)->pool=%d\n",
|
||||
d->domain_id, op->cpupool_id);
|
||||
ret = -ENOENT;
|
||||
spin_lock(&cpupool_lock);
|
||||
c = cpupool_find_by_id(op->cpupool_id, 1);
|
||||
if ( (c != NULL) && cpus_weight(c->cpu_valid) )
|
||||
{
|
||||
d->cpupool->n_dom--;
|
||||
ret = sched_move_domain(d, c);
|
||||
if ( ret )
|
||||
d->cpupool->n_dom++;
|
||||
else
|
||||
c->n_dom++;
|
||||
}
|
||||
spin_unlock(&cpupool_lock);
|
||||
printk(XENLOG_DEBUG "cpupool move_domain(dom=%d)->pool=%d ret %d\n",
|
||||
d->domain_id, op->cpupool_id, ret);
|
||||
rcu_unlock_domain(d);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_CPUPOOL_OP_FREEINFO:
|
||||
{
|
||||
cpumask_to_xenctl_cpumap(&(op->cpumap),
|
||||
&cpupool_free_cpus);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void schedule_dump(struct cpupool *c);
|
||||
|
||||
void dump_runq(unsigned char key)
|
||||
{
|
||||
unsigned long flags;
|
||||
s_time_t now = NOW();
|
||||
struct cpupool **c;
|
||||
|
||||
spin_lock(&cpupool_lock);
|
||||
local_irq_save(flags);
|
||||
|
||||
printk("sched_smt_power_savings: %s\n",
|
||||
sched_smt_power_savings? "enabled":"disabled");
|
||||
printk("NOW=0x%08X%08X\n", (u32)(now>>32), (u32)now);
|
||||
|
||||
printk("Idle cpupool:\n");
|
||||
schedule_dump(NULL);
|
||||
|
||||
for_each_cpupool(c)
|
||||
{
|
||||
printk("Cpupool %d:\n", (*c)->cpupool_id);
|
||||
schedule_dump(*c);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
spin_unlock(&cpupool_lock);
|
||||
}
|
||||
|
||||
static int __init cpupool_init(void)
|
||||
{
|
||||
cpupool_free_cpus = cpu_online_map;
|
||||
cpupool_list = NULL;
|
||||
return 0;
|
||||
}
|
||||
__initcall(cpupool_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -218,6 +218,7 @@ struct domain *domain_create(
|
||||
enum { INIT_xsm = 1u<<0, INIT_rangeset = 1u<<1, INIT_evtchn = 1u<<2,
|
||||
INIT_gnttab = 1u<<3, INIT_arch = 1u<<4 };
|
||||
int init_status = 0;
|
||||
int poolid = CPUPOOLID_NONE;
|
||||
|
||||
if ( (d = alloc_domain_struct()) == NULL )
|
||||
return NULL;
|
||||
@@ -282,6 +283,8 @@ struct domain *domain_create(
|
||||
if ( grant_table_create(d) != 0 )
|
||||
goto fail;
|
||||
init_status |= INIT_gnttab;
|
||||
|
||||
poolid = 0;
|
||||
}
|
||||
|
||||
if ( arch_domain_create(d, domcr_flags) != 0 )
|
||||
@@ -293,6 +296,9 @@ struct domain *domain_create(
|
||||
if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
|
||||
goto fail;
|
||||
|
||||
if ( cpupool_add_domain(d, poolid) != 0 )
|
||||
goto fail;
|
||||
|
||||
if ( sched_init_domain(d) != 0 )
|
||||
goto fail;
|
||||
|
||||
@@ -601,6 +607,8 @@ static void complete_domain_destroy(struct rcu_head *head)
|
||||
|
||||
rangeset_domain_destroy(d);
|
||||
|
||||
cpupool_rm_domain(d);
|
||||
|
||||
sched_destroy_domain(d);
|
||||
|
||||
/* Free page used by xen oprofile buffer. */
|
||||
|
||||
+17
-4
@@ -11,6 +11,7 @@
|
||||
#include <xen/lib.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/sched-if.h>
|
||||
#include <xen/domain.h>
|
||||
#include <xen/event.h>
|
||||
#include <xen/domain_page.h>
|
||||
@@ -140,10 +141,12 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
|
||||
info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT);
|
||||
BUG_ON(SHARED_M2P(info->shared_info_frame));
|
||||
|
||||
info->cpupool = d->cpupool ? d->cpupool->cpupool_id : CPUPOOLID_NONE;
|
||||
|
||||
memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
|
||||
}
|
||||
|
||||
static unsigned int default_vcpu0_location(void)
|
||||
static unsigned int default_vcpu0_location(cpumask_t *online)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
@@ -173,7 +176,7 @@ static unsigned int default_vcpu0_location(void)
|
||||
if ( cpus_weight(per_cpu(cpu_sibling_map, 0)) > 1 )
|
||||
cpu = next_cpu(cpu, per_cpu(cpu_sibling_map, 0));
|
||||
cpu_exclude_map = per_cpu(cpu_sibling_map, 0);
|
||||
for_each_online_cpu ( i )
|
||||
for_each_cpu_mask(i, *online)
|
||||
{
|
||||
if ( cpu_isset(i, cpu_exclude_map) )
|
||||
continue;
|
||||
@@ -450,6 +453,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
{
|
||||
struct domain *d;
|
||||
unsigned int i, max = op->u.max_vcpus.max, cpu;
|
||||
cpumask_t *online;
|
||||
|
||||
ret = -ESRCH;
|
||||
if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
|
||||
@@ -498,6 +502,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
goto maxvcpu_out;
|
||||
|
||||
ret = -ENOMEM;
|
||||
online = (d->cpupool == NULL) ? &cpu_online_map : &d->cpupool->cpu_valid;
|
||||
if ( max > d->max_vcpus )
|
||||
{
|
||||
struct vcpu **vcpus;
|
||||
@@ -521,8 +526,8 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
continue;
|
||||
|
||||
cpu = (i == 0) ?
|
||||
default_vcpu0_location() :
|
||||
cycle_cpu(d->vcpu[i-1]->processor, cpu_online_map);
|
||||
default_vcpu0_location(online) :
|
||||
cycle_cpu(d->vcpu[i-1]->processor, *online);
|
||||
|
||||
if ( alloc_vcpu(d, i, cpu) == NULL )
|
||||
goto maxvcpu_out;
|
||||
@@ -961,6 +966,14 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_cpupool_op:
|
||||
{
|
||||
ret = cpupool_do_domctl(&op->u.cpupool_op);
|
||||
if ( (ret == 0) && copy_to_guest(u_domctl, op, 1) )
|
||||
ret = -EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = arch_do_domctl(op, u_domctl);
|
||||
break;
|
||||
|
||||
+276
-139
@@ -70,11 +70,15 @@
|
||||
/*
|
||||
* Useful macros
|
||||
*/
|
||||
#define CSCHED_PRIV(_ops) \
|
||||
((struct csched_private *)((_ops)->sched_data))
|
||||
#define CSCHED_PCPU(_c) \
|
||||
((struct csched_pcpu *)per_cpu(schedule_data, _c).sched_priv)
|
||||
#define CSCHED_VCPU(_vcpu) ((struct csched_vcpu *) (_vcpu)->sched_priv)
|
||||
#define CSCHED_DOM(_dom) ((struct csched_dom *) (_dom)->sched_priv)
|
||||
#define RUNQ(_cpu) (&(CSCHED_PCPU(_cpu)->runq))
|
||||
#define CSCHED_CPUONLINE(_pool) \
|
||||
(((_pool) == NULL) ? &cpupool_free_cpus : &(_pool)->cpu_valid)
|
||||
|
||||
|
||||
/*
|
||||
@@ -160,19 +164,22 @@ struct csched_private {
|
||||
struct timer master_ticker;
|
||||
unsigned int master;
|
||||
cpumask_t idlers;
|
||||
cpumask_t cpus;
|
||||
uint32_t weight;
|
||||
uint32_t credit;
|
||||
int credit_balance;
|
||||
uint32_t runq_sort;
|
||||
int ticker_active;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
static struct csched_private csched_priv;
|
||||
static struct csched_private *csched_priv0 = NULL;
|
||||
|
||||
static void csched_tick(void *_cpu);
|
||||
static void csched_acct(void *dummy);
|
||||
|
||||
static inline int
|
||||
__vcpu_on_runq(struct csched_vcpu *svc)
|
||||
@@ -238,6 +245,7 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
|
||||
{
|
||||
struct csched_vcpu * const cur =
|
||||
CSCHED_VCPU(per_cpu(schedule_data, cpu).curr);
|
||||
struct csched_private *prv = CSCHED_PRIV(per_cpu(scheduler, cpu));
|
||||
cpumask_t mask;
|
||||
|
||||
ASSERT(cur);
|
||||
@@ -264,7 +272,7 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
|
||||
*/
|
||||
if ( cur->pri > CSCHED_PRI_IDLE )
|
||||
{
|
||||
if ( cpus_empty(csched_priv.idlers) )
|
||||
if ( cpus_empty(prv->idlers) )
|
||||
{
|
||||
CSCHED_STAT_CRANK(tickle_idlers_none);
|
||||
}
|
||||
@@ -272,7 +280,7 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
|
||||
{
|
||||
cpumask_t idle_mask;
|
||||
|
||||
cpus_and(idle_mask, csched_priv.idlers, new->vcpu->cpu_affinity);
|
||||
cpus_and(idle_mask, prv->idlers, new->vcpu->cpu_affinity);
|
||||
if ( !cpus_empty(idle_mask) )
|
||||
{
|
||||
CSCHED_STAT_CRANK(tickle_idlers_some);
|
||||
@@ -294,40 +302,80 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
|
||||
cpumask_raise_softirq(mask, SCHEDULE_SOFTIRQ);
|
||||
}
|
||||
|
||||
static int
|
||||
csched_pcpu_init(int cpu)
|
||||
static void
|
||||
csched_free_pdata(struct scheduler *ops, void *pcpu, int cpu)
|
||||
{
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
struct csched_pcpu *spc = pcpu;
|
||||
unsigned long flags;
|
||||
|
||||
if ( spc == NULL )
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&prv->lock, flags);
|
||||
|
||||
prv->credit -= CSCHED_CREDITS_PER_ACCT;
|
||||
prv->ncpus--;
|
||||
cpu_clear(cpu, prv->idlers);
|
||||
cpu_clear(cpu, prv->cpus);
|
||||
if ( (prv->master == cpu) && (prv->ncpus > 0) )
|
||||
{
|
||||
prv->master = first_cpu(prv->cpus);
|
||||
migrate_timer(&prv->master_ticker, prv->master);
|
||||
}
|
||||
kill_timer(&spc->ticker);
|
||||
if ( prv->ncpus == 0 )
|
||||
kill_timer(&prv->master_ticker);
|
||||
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
|
||||
xfree(spc);
|
||||
}
|
||||
|
||||
static void *
|
||||
csched_alloc_pdata(struct scheduler *ops, int cpu)
|
||||
{
|
||||
struct csched_pcpu *spc;
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
unsigned long flags;
|
||||
|
||||
/* Allocate per-PCPU info */
|
||||
spc = xmalloc(struct csched_pcpu);
|
||||
if ( spc == NULL )
|
||||
return -1;
|
||||
return NULL;
|
||||
memset(spc, 0, sizeof(*spc));
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
spin_lock_irqsave(&prv->lock, flags);
|
||||
|
||||
/* Initialize/update system-wide config */
|
||||
csched_priv.credit += CSCHED_CREDITS_PER_ACCT;
|
||||
if ( csched_priv.ncpus <= cpu )
|
||||
csched_priv.ncpus = cpu + 1;
|
||||
if ( csched_priv.master >= csched_priv.ncpus )
|
||||
csched_priv.master = cpu;
|
||||
prv->credit += CSCHED_CREDITS_PER_ACCT;
|
||||
prv->ncpus++;
|
||||
cpu_set(cpu, prv->cpus);
|
||||
if ( (prv->ncpus == 1) && (prv != csched_priv0) )
|
||||
{
|
||||
prv->master = cpu;
|
||||
init_timer( &prv->master_ticker, csched_acct, prv, cpu);
|
||||
prv->ticker_active = 2;
|
||||
}
|
||||
|
||||
init_timer(&spc->ticker, csched_tick, (void *)(unsigned long)cpu, cpu);
|
||||
|
||||
if ( prv == csched_priv0 )
|
||||
prv->master = first_cpu(prv->cpus);
|
||||
|
||||
INIT_LIST_HEAD(&spc->runq);
|
||||
spc->runq_sort_last = csched_priv.runq_sort;
|
||||
spc->runq_sort_last = prv->runq_sort;
|
||||
spc->idle_bias = NR_CPUS - 1;
|
||||
per_cpu(schedule_data, cpu).sched_priv = spc;
|
||||
if ( per_cpu(schedule_data, cpu).sched_priv == NULL )
|
||||
per_cpu(schedule_data, cpu).sched_priv = spc;
|
||||
|
||||
/* Start off idling... */
|
||||
BUG_ON(!is_idle_vcpu(per_cpu(schedule_data, cpu).curr));
|
||||
cpu_set(cpu, csched_priv.idlers);
|
||||
cpu_set(cpu, prv->idlers);
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
|
||||
return 0;
|
||||
return spc;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -400,17 +448,19 @@ __csched_vcpu_is_migrateable(struct vcpu *vc, int dest_cpu)
|
||||
}
|
||||
|
||||
static int
|
||||
_csched_cpu_pick(struct vcpu *vc, bool_t commit)
|
||||
_csched_cpu_pick(struct scheduler *ops, struct vcpu *vc, bool_t commit)
|
||||
{
|
||||
cpumask_t cpus;
|
||||
cpumask_t idlers;
|
||||
cpumask_t *online;
|
||||
int cpu;
|
||||
|
||||
/*
|
||||
* Pick from online CPUs in VCPU's affinity mask, giving a
|
||||
* preference to its current processor if it's in there.
|
||||
*/
|
||||
cpus_and(cpus, cpu_online_map, vc->cpu_affinity);
|
||||
online = CSCHED_CPUONLINE(vc->domain->cpupool);
|
||||
cpus_and(cpus, *online, vc->cpu_affinity);
|
||||
cpu = cpu_isset(vc->processor, cpus)
|
||||
? vc->processor
|
||||
: cycle_cpu(vc->processor, cpus);
|
||||
@@ -428,7 +478,7 @@ _csched_cpu_pick(struct vcpu *vc, bool_t commit)
|
||||
* like run two VCPUs on co-hyperthreads while there are idle cores
|
||||
* or sockets.
|
||||
*/
|
||||
cpus_and(idlers, cpu_online_map, csched_priv.idlers);
|
||||
cpus_and(idlers, cpu_online_map, CSCHED_PRIV(ops)->idlers);
|
||||
cpu_set(cpu, idlers);
|
||||
cpus_and(cpus, cpus, idlers);
|
||||
cpu_clear(cpu, cpus);
|
||||
@@ -474,18 +524,18 @@ _csched_cpu_pick(struct vcpu *vc, bool_t commit)
|
||||
}
|
||||
|
||||
static int
|
||||
csched_cpu_pick(struct vcpu *vc)
|
||||
csched_cpu_pick(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
return _csched_cpu_pick(vc, 1);
|
||||
return _csched_cpu_pick(ops, vc, 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__csched_vcpu_acct_start(struct csched_vcpu *svc)
|
||||
__csched_vcpu_acct_start(struct csched_private *prv, struct csched_vcpu *svc)
|
||||
{
|
||||
struct csched_dom * const sdom = svc->sdom;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
spin_lock_irqsave(&prv->lock, flags);
|
||||
|
||||
if ( list_empty(&svc->active_vcpu_elem) )
|
||||
{
|
||||
@@ -496,16 +546,17 @@ __csched_vcpu_acct_start(struct csched_vcpu *svc)
|
||||
list_add(&svc->active_vcpu_elem, &sdom->active_vcpu);
|
||||
if ( list_empty(&sdom->active_sdom_elem) )
|
||||
{
|
||||
list_add(&sdom->active_sdom_elem, &csched_priv.active_sdom);
|
||||
csched_priv.weight += sdom->weight;
|
||||
list_add(&sdom->active_sdom_elem, &prv->active_sdom);
|
||||
prv->weight += sdom->weight;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__csched_vcpu_acct_stop_locked(struct csched_vcpu *svc)
|
||||
__csched_vcpu_acct_stop_locked(struct csched_private *prv,
|
||||
struct csched_vcpu *svc)
|
||||
{
|
||||
struct csched_dom * const sdom = svc->sdom;
|
||||
|
||||
@@ -518,16 +569,17 @@ __csched_vcpu_acct_stop_locked(struct csched_vcpu *svc)
|
||||
list_del_init(&svc->active_vcpu_elem);
|
||||
if ( list_empty(&sdom->active_vcpu) )
|
||||
{
|
||||
BUG_ON( csched_priv.weight < sdom->weight );
|
||||
BUG_ON( prv->weight < sdom->weight );
|
||||
list_del_init(&sdom->active_sdom_elem);
|
||||
csched_priv.weight -= sdom->weight;
|
||||
prv->weight -= sdom->weight;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_acct(unsigned int cpu)
|
||||
csched_vcpu_acct(struct csched_private *prv, unsigned int cpu)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(current);
|
||||
struct scheduler *ops = per_cpu(scheduler, cpu);
|
||||
|
||||
ASSERT( current->processor == cpu );
|
||||
ASSERT( svc->sdom != NULL );
|
||||
@@ -556,9 +608,9 @@ csched_vcpu_acct(unsigned int cpu)
|
||||
*/
|
||||
if ( list_empty(&svc->active_vcpu_elem) )
|
||||
{
|
||||
__csched_vcpu_acct_start(svc);
|
||||
__csched_vcpu_acct_start(prv, svc);
|
||||
}
|
||||
else if ( _csched_cpu_pick(current, 0) != cpu )
|
||||
else if ( _csched_cpu_pick(ops, current, 0) != cpu )
|
||||
{
|
||||
CSCHED_VCPU_STAT_CRANK(svc, migrate_r);
|
||||
CSCHED_STAT_CRANK(migrate_running);
|
||||
@@ -567,66 +619,75 @@ csched_vcpu_acct(unsigned int cpu)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
csched_vcpu_init(struct vcpu *vc)
|
||||
static void *
|
||||
csched_alloc_vdata(struct scheduler *ops, struct vcpu *vc, void *dd)
|
||||
{
|
||||
struct domain * const dom = vc->domain;
|
||||
struct csched_dom *sdom = CSCHED_DOM(dom);
|
||||
struct csched_vcpu *svc;
|
||||
|
||||
CSCHED_STAT_CRANK(vcpu_init);
|
||||
|
||||
/* Allocate per-VCPU info */
|
||||
svc = xmalloc(struct csched_vcpu);
|
||||
if ( svc == NULL )
|
||||
return -1;
|
||||
return NULL;
|
||||
memset(svc, 0, sizeof(*svc));
|
||||
|
||||
INIT_LIST_HEAD(&svc->runq_elem);
|
||||
INIT_LIST_HEAD(&svc->active_vcpu_elem);
|
||||
svc->sdom = sdom;
|
||||
svc->sdom = dd;
|
||||
svc->vcpu = vc;
|
||||
atomic_set(&svc->credit, 0);
|
||||
svc->flags = 0U;
|
||||
svc->pri = is_idle_domain(dom) ? CSCHED_PRI_IDLE : CSCHED_PRI_TS_UNDER;
|
||||
svc->pri = is_idle_domain(vc->domain) ?
|
||||
CSCHED_PRI_IDLE : CSCHED_PRI_TS_UNDER;
|
||||
CSCHED_VCPU_STATS_RESET(svc);
|
||||
vc->sched_priv = svc;
|
||||
|
||||
/* Allocate per-PCPU info */
|
||||
if ( unlikely(!CSCHED_PCPU(vc->processor)) )
|
||||
{
|
||||
if ( csched_pcpu_init(vc->processor) != 0 )
|
||||
return -1;
|
||||
}
|
||||
|
||||
CSCHED_VCPU_CHECK(vc);
|
||||
return 0;
|
||||
CSCHED_STAT_CRANK(vcpu_init);
|
||||
return svc;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_destroy(struct vcpu *vc)
|
||||
csched_vcpu_insert(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu *svc = vc->sched_priv;
|
||||
|
||||
if ( !__vcpu_on_runq(svc) && vcpu_runnable(vc) && !vc->is_running )
|
||||
__runq_insert(vc->processor, svc);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_free_vdata(struct scheduler *ops, void *priv)
|
||||
{
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
struct csched_vcpu *svc = priv;
|
||||
unsigned long flags;
|
||||
|
||||
if ( __vcpu_on_runq(svc) )
|
||||
__runq_remove(svc);
|
||||
|
||||
spin_lock_irqsave(&(prv->lock), flags);
|
||||
|
||||
if ( !list_empty(&svc->active_vcpu_elem) )
|
||||
__csched_vcpu_acct_stop_locked(prv, svc);
|
||||
|
||||
spin_unlock_irqrestore(&(prv->lock), flags);
|
||||
|
||||
xfree(svc);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_destroy(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
struct csched_dom * const sdom = svc->sdom;
|
||||
unsigned long flags;
|
||||
|
||||
CSCHED_STAT_CRANK(vcpu_destroy);
|
||||
|
||||
BUG_ON( sdom == NULL );
|
||||
BUG_ON( !list_empty(&svc->runq_elem) );
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
|
||||
if ( !list_empty(&svc->active_vcpu_elem) )
|
||||
__csched_vcpu_acct_stop_locked(svc);
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
|
||||
xfree(svc);
|
||||
csched_free_vdata(ops, svc);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_sleep(struct vcpu *vc)
|
||||
csched_vcpu_sleep(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
|
||||
@@ -641,7 +702,7 @@ csched_vcpu_sleep(struct vcpu *vc)
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_wake(struct vcpu *vc)
|
||||
csched_vcpu_wake(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
const unsigned int cpu = vc->processor;
|
||||
@@ -697,10 +758,12 @@ csched_vcpu_wake(struct vcpu *vc)
|
||||
|
||||
static int
|
||||
csched_dom_cntl(
|
||||
struct scheduler *ops,
|
||||
struct domain *d,
|
||||
struct xen_domctl_scheduler_op *op)
|
||||
{
|
||||
struct csched_dom * const sdom = CSCHED_DOM(d);
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
unsigned long flags;
|
||||
|
||||
if ( op->cmd == XEN_DOMCTL_SCHEDOP_getinfo )
|
||||
@@ -712,14 +775,14 @@ csched_dom_cntl(
|
||||
{
|
||||
ASSERT(op->cmd == XEN_DOMCTL_SCHEDOP_putinfo);
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
spin_lock_irqsave(&prv->lock, flags);
|
||||
|
||||
if ( op->u.credit.weight != 0 )
|
||||
{
|
||||
if ( !list_empty(&sdom->active_sdom_elem) )
|
||||
{
|
||||
csched_priv.weight -= sdom->weight;
|
||||
csched_priv.weight += op->u.credit.weight;
|
||||
prv->weight -= sdom->weight;
|
||||
prv->weight += op->u.credit.weight;
|
||||
}
|
||||
sdom->weight = op->u.credit.weight;
|
||||
}
|
||||
@@ -727,25 +790,20 @@ csched_dom_cntl(
|
||||
if ( op->u.credit.cap != (uint16_t)~0U )
|
||||
sdom->cap = op->u.credit.cap;
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
csched_dom_init(struct domain *dom)
|
||||
static void *
|
||||
csched_alloc_domdata(struct scheduler *ops, struct domain *dom)
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
|
||||
CSCHED_STAT_CRANK(dom_init);
|
||||
|
||||
if ( is_idle_domain(dom) )
|
||||
return 0;
|
||||
|
||||
sdom = xmalloc(struct csched_dom);
|
||||
if ( sdom == NULL )
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
memset(sdom, 0, sizeof(*sdom));
|
||||
|
||||
/* Initialize credit and weight */
|
||||
@@ -755,16 +813,40 @@ csched_dom_init(struct domain *dom)
|
||||
sdom->dom = dom;
|
||||
sdom->weight = CSCHED_DEFAULT_WEIGHT;
|
||||
sdom->cap = 0U;
|
||||
|
||||
return (void *)sdom;
|
||||
}
|
||||
|
||||
static int
|
||||
csched_dom_init(struct scheduler *ops, struct domain *dom)
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
|
||||
CSCHED_STAT_CRANK(dom_init);
|
||||
|
||||
if ( is_idle_domain(dom) )
|
||||
return 0;
|
||||
|
||||
sdom = csched_alloc_domdata(ops, dom);
|
||||
if ( sdom == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
dom->sched_priv = sdom;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dom_destroy(struct domain *dom)
|
||||
csched_free_domdata(struct scheduler *ops, void *data)
|
||||
{
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dom_destroy(struct scheduler *ops, struct domain *dom)
|
||||
{
|
||||
CSCHED_STAT_CRANK(dom_destroy);
|
||||
xfree(CSCHED_DOM(dom));
|
||||
csched_free_domdata(ops, CSCHED_DOM(dom));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -775,7 +857,7 @@ csched_dom_destroy(struct domain *dom)
|
||||
* remember the last UNDER to make the move up operation O(1).
|
||||
*/
|
||||
static void
|
||||
csched_runq_sort(unsigned int cpu)
|
||||
csched_runq_sort(struct csched_private *prv, unsigned int cpu)
|
||||
{
|
||||
struct csched_pcpu * const spc = CSCHED_PCPU(cpu);
|
||||
struct list_head *runq, *elem, *next, *last_under;
|
||||
@@ -783,7 +865,7 @@ csched_runq_sort(unsigned int cpu)
|
||||
unsigned long flags;
|
||||
int sort_epoch;
|
||||
|
||||
sort_epoch = csched_priv.runq_sort;
|
||||
sort_epoch = prv->runq_sort;
|
||||
if ( sort_epoch == spc->runq_sort_last )
|
||||
return;
|
||||
|
||||
@@ -820,6 +902,7 @@ csched_runq_sort(unsigned int cpu)
|
||||
static void
|
||||
csched_acct(void* dummy)
|
||||
{
|
||||
struct csched_private *prv = dummy;
|
||||
unsigned long flags;
|
||||
struct list_head *iter_vcpu, *next_vcpu;
|
||||
struct list_head *iter_sdom, *next_sdom;
|
||||
@@ -836,22 +919,22 @@ csched_acct(void* dummy)
|
||||
int credit;
|
||||
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
spin_lock_irqsave(&prv->lock, flags);
|
||||
|
||||
weight_total = csched_priv.weight;
|
||||
credit_total = csched_priv.credit;
|
||||
weight_total = prv->weight;
|
||||
credit_total = prv->credit;
|
||||
|
||||
/* Converge balance towards 0 when it drops negative */
|
||||
if ( csched_priv.credit_balance < 0 )
|
||||
if ( prv->credit_balance < 0 )
|
||||
{
|
||||
credit_total -= csched_priv.credit_balance;
|
||||
credit_total -= prv->credit_balance;
|
||||
CSCHED_STAT_CRANK(acct_balance);
|
||||
}
|
||||
|
||||
if ( unlikely(weight_total == 0) )
|
||||
{
|
||||
csched_priv.credit_balance = 0;
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
prv->credit_balance = 0;
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
CSCHED_STAT_CRANK(acct_no_work);
|
||||
goto out;
|
||||
}
|
||||
@@ -863,7 +946,7 @@ csched_acct(void* dummy)
|
||||
credit_xtra = 0;
|
||||
credit_cap = 0U;
|
||||
|
||||
list_for_each_safe( iter_sdom, next_sdom, &csched_priv.active_sdom )
|
||||
list_for_each_safe( iter_sdom, next_sdom, &prv->active_sdom )
|
||||
{
|
||||
sdom = list_entry(iter_sdom, struct csched_dom, active_sdom_elem);
|
||||
|
||||
@@ -883,9 +966,9 @@ csched_acct(void* dummy)
|
||||
* only when the system-wide credit balance is negative.
|
||||
*/
|
||||
credit_peak = sdom->active_vcpu_count * CSCHED_CREDITS_PER_ACCT;
|
||||
if ( csched_priv.credit_balance < 0 )
|
||||
if ( prv->credit_balance < 0 )
|
||||
{
|
||||
credit_peak += ( ( -csched_priv.credit_balance * sdom->weight) +
|
||||
credit_peak += ( ( -prv->credit_balance * sdom->weight) +
|
||||
(weight_total - 1)
|
||||
) / weight_total;
|
||||
}
|
||||
@@ -927,7 +1010,7 @@ csched_acct(void* dummy)
|
||||
*/
|
||||
CSCHED_STAT_CRANK(acct_reorder);
|
||||
list_del(&sdom->active_sdom_elem);
|
||||
list_add(&sdom->active_sdom_elem, &csched_priv.active_sdom);
|
||||
list_add(&sdom->active_sdom_elem, &prv->active_sdom);
|
||||
}
|
||||
|
||||
credit_fair = credit_peak;
|
||||
@@ -993,7 +1076,7 @@ csched_acct(void* dummy)
|
||||
/* Upper bound on credits means VCPU stops earning */
|
||||
if ( credit > CSCHED_CREDITS_PER_TSLICE )
|
||||
{
|
||||
__csched_vcpu_acct_stop_locked(svc);
|
||||
__csched_vcpu_acct_stop_locked(prv, svc);
|
||||
credit = 0;
|
||||
atomic_set(&svc->credit, credit);
|
||||
}
|
||||
@@ -1005,15 +1088,15 @@ csched_acct(void* dummy)
|
||||
}
|
||||
}
|
||||
|
||||
csched_priv.credit_balance = credit_balance;
|
||||
prv->credit_balance = credit_balance;
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
|
||||
/* Inform each CPU that its runq needs to be sorted */
|
||||
csched_priv.runq_sort++;
|
||||
prv->runq_sort++;
|
||||
|
||||
out:
|
||||
set_timer( &csched_priv.master_ticker, NOW() +
|
||||
set_timer( &prv->master_ticker, NOW() +
|
||||
MILLISECS(CSCHED_MSECS_PER_TICK) * CSCHED_TICKS_PER_ACCT );
|
||||
}
|
||||
|
||||
@@ -1022,6 +1105,7 @@ csched_tick(void *_cpu)
|
||||
{
|
||||
unsigned int cpu = (unsigned long)_cpu;
|
||||
struct csched_pcpu *spc = CSCHED_PCPU(cpu);
|
||||
struct csched_private *prv = CSCHED_PRIV(per_cpu(scheduler, cpu));
|
||||
|
||||
spc->tick++;
|
||||
|
||||
@@ -1029,7 +1113,7 @@ csched_tick(void *_cpu)
|
||||
* Accounting for running VCPU
|
||||
*/
|
||||
if ( !is_idle_vcpu(current) )
|
||||
csched_vcpu_acct(cpu);
|
||||
csched_vcpu_acct(prv, cpu);
|
||||
|
||||
/*
|
||||
* Check if runq needs to be sorted
|
||||
@@ -1038,7 +1122,7 @@ csched_tick(void *_cpu)
|
||||
* modified priorities. This is a special O(n) sort and runs at most
|
||||
* once per accounting period (currently 30 milliseconds).
|
||||
*/
|
||||
csched_runq_sort(cpu);
|
||||
csched_runq_sort(prv, cpu);
|
||||
|
||||
set_timer(&spc->ticker, NOW() + MILLISECS(CSCHED_MSECS_PER_TICK));
|
||||
}
|
||||
@@ -1091,16 +1175,19 @@ csched_runq_steal(int peer_cpu, int cpu, int pri)
|
||||
}
|
||||
|
||||
static struct csched_vcpu *
|
||||
csched_load_balance(int cpu, struct csched_vcpu *snext)
|
||||
csched_load_balance(struct csched_private *prv, int cpu,
|
||||
struct csched_vcpu *snext)
|
||||
{
|
||||
struct csched_vcpu *speer;
|
||||
cpumask_t workers;
|
||||
cpumask_t *online;
|
||||
int peer_cpu;
|
||||
|
||||
BUG_ON( cpu != snext->vcpu->processor );
|
||||
online = CSCHED_CPUONLINE(per_cpu(cpupool, cpu));
|
||||
|
||||
/* If this CPU is going offline we shouldn't steal work. */
|
||||
if ( unlikely(!cpu_online(cpu)) )
|
||||
if ( unlikely(!cpu_isset(cpu, *online)) )
|
||||
goto out;
|
||||
|
||||
if ( snext->pri == CSCHED_PRI_IDLE )
|
||||
@@ -1114,7 +1201,7 @@ csched_load_balance(int cpu, struct csched_vcpu *snext)
|
||||
* Peek at non-idling CPUs in the system, starting with our
|
||||
* immediate neighbour.
|
||||
*/
|
||||
cpus_andnot(workers, cpu_online_map, csched_priv.idlers);
|
||||
cpus_andnot(workers, *online, prv->idlers);
|
||||
cpu_clear(cpu, workers);
|
||||
peer_cpu = cpu;
|
||||
|
||||
@@ -1156,11 +1243,12 @@ csched_load_balance(int cpu, struct csched_vcpu *snext)
|
||||
* fast for the common case.
|
||||
*/
|
||||
static struct task_slice
|
||||
csched_schedule(s_time_t now)
|
||||
csched_schedule(struct scheduler *ops, s_time_t now)
|
||||
{
|
||||
const int cpu = smp_processor_id();
|
||||
struct list_head * const runq = RUNQ(cpu);
|
||||
struct csched_vcpu * const scurr = CSCHED_VCPU(current);
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
struct csched_vcpu *snext;
|
||||
struct task_slice ret;
|
||||
|
||||
@@ -1207,7 +1295,7 @@ csched_schedule(s_time_t now)
|
||||
if ( snext->pri > CSCHED_PRI_TS_OVER )
|
||||
__runq_remove(snext);
|
||||
else
|
||||
snext = csched_load_balance(cpu, snext);
|
||||
snext = csched_load_balance(prv, cpu, snext);
|
||||
|
||||
/*
|
||||
* Update idlers mask if necessary. When we're idling, other CPUs
|
||||
@@ -1215,12 +1303,12 @@ csched_schedule(s_time_t now)
|
||||
*/
|
||||
if ( snext->pri == CSCHED_PRI_IDLE )
|
||||
{
|
||||
if ( !cpu_isset(cpu, csched_priv.idlers) )
|
||||
cpu_set(cpu, csched_priv.idlers);
|
||||
if ( !cpu_isset(cpu, prv->idlers) )
|
||||
cpu_set(cpu, prv->idlers);
|
||||
}
|
||||
else if ( cpu_isset(cpu, csched_priv.idlers) )
|
||||
else if ( cpu_isset(cpu, prv->idlers) )
|
||||
{
|
||||
cpu_clear(cpu, csched_priv.idlers);
|
||||
cpu_clear(cpu, prv->idlers);
|
||||
}
|
||||
|
||||
if ( !is_idle_vcpu(snext->vcpu) )
|
||||
@@ -1267,7 +1355,7 @@ csched_dump_vcpu(struct csched_vcpu *svc)
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dump_pcpu(int cpu)
|
||||
csched_dump_pcpu(struct scheduler *ops, int cpu)
|
||||
{
|
||||
struct list_head *runq, *iter;
|
||||
struct csched_pcpu *spc;
|
||||
@@ -1305,9 +1393,10 @@ csched_dump_pcpu(int cpu)
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dump(void)
|
||||
csched_dump(struct scheduler *ops)
|
||||
{
|
||||
struct list_head *iter_sdom, *iter_svc;
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
int loop;
|
||||
#define idlers_buf keyhandler_scratch
|
||||
|
||||
@@ -1324,12 +1413,12 @@ csched_dump(void)
|
||||
"\tticks per tslice = %d\n"
|
||||
"\tticks per acct = %d\n"
|
||||
"\tmigration delay = %uus\n",
|
||||
csched_priv.ncpus,
|
||||
csched_priv.master,
|
||||
csched_priv.credit,
|
||||
csched_priv.credit_balance,
|
||||
csched_priv.weight,
|
||||
csched_priv.runq_sort,
|
||||
prv->ncpus,
|
||||
prv->master,
|
||||
prv->credit,
|
||||
prv->credit_balance,
|
||||
prv->weight,
|
||||
prv->runq_sort,
|
||||
CSCHED_DEFAULT_WEIGHT,
|
||||
CSCHED_MSECS_PER_TICK,
|
||||
CSCHED_CREDITS_PER_MSEC,
|
||||
@@ -1337,12 +1426,12 @@ csched_dump(void)
|
||||
CSCHED_TICKS_PER_ACCT,
|
||||
vcpu_migration_delay);
|
||||
|
||||
cpumask_scnprintf(idlers_buf, sizeof(idlers_buf), csched_priv.idlers);
|
||||
cpumask_scnprintf(idlers_buf, sizeof(idlers_buf), prv->idlers);
|
||||
printk("idlers: %s\n", idlers_buf);
|
||||
|
||||
printk("active vcpus:\n");
|
||||
loop = 0;
|
||||
list_for_each( iter_sdom, &csched_priv.active_sdom )
|
||||
list_for_each( iter_sdom, &prv->active_sdom )
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
sdom = list_entry(iter_sdom, struct csched_dom, active_sdom_elem);
|
||||
@@ -1359,18 +1448,30 @@ csched_dump(void)
|
||||
#undef idlers_buf
|
||||
}
|
||||
|
||||
static void
|
||||
csched_init(void)
|
||||
static int
|
||||
csched_init(struct scheduler *ops, int pool0)
|
||||
{
|
||||
spin_lock_init(&csched_priv.lock);
|
||||
INIT_LIST_HEAD(&csched_priv.active_sdom);
|
||||
csched_priv.ncpus = 0;
|
||||
csched_priv.master = UINT_MAX;
|
||||
cpus_clear(csched_priv.idlers);
|
||||
csched_priv.weight = 0U;
|
||||
csched_priv.credit = 0U;
|
||||
csched_priv.credit_balance = 0;
|
||||
csched_priv.runq_sort = 0U;
|
||||
struct csched_private *prv;
|
||||
|
||||
prv = xmalloc(struct csched_private);
|
||||
if ( prv == NULL )
|
||||
return 1;
|
||||
memset(prv, 0, sizeof(*prv));
|
||||
if ( pool0 )
|
||||
csched_priv0 = prv;
|
||||
ops->sched_data = prv;
|
||||
spin_lock_init(&prv->lock);
|
||||
INIT_LIST_HEAD(&prv->active_sdom);
|
||||
prv->ncpus = 0;
|
||||
prv->master = UINT_MAX;
|
||||
cpus_clear(prv->idlers);
|
||||
prv->weight = 0U;
|
||||
prv->credit = 0U;
|
||||
prv->credit_balance = 0;
|
||||
prv->runq_sort = 0U;
|
||||
prv->ticker_active = (csched_priv0 == prv) ? 0 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Tickers cannot be kicked until SMP subsystem is alive. */
|
||||
@@ -1380,54 +1481,83 @@ static __init int csched_start_tickers(void)
|
||||
unsigned int cpu;
|
||||
|
||||
/* Is the credit scheduler initialised? */
|
||||
if ( csched_priv.ncpus == 0 )
|
||||
if ( (csched_priv0 == NULL) || (csched_priv0->ncpus == 0) )
|
||||
return 0;
|
||||
|
||||
csched_priv0->ticker_active = 1;
|
||||
|
||||
for_each_online_cpu ( cpu )
|
||||
{
|
||||
spc = CSCHED_PCPU(cpu);
|
||||
set_timer(&spc->ticker, NOW() + MILLISECS(CSCHED_MSECS_PER_TICK));
|
||||
}
|
||||
|
||||
init_timer( &csched_priv.master_ticker, csched_acct, NULL,
|
||||
csched_priv.master);
|
||||
init_timer( &csched_priv0->master_ticker, csched_acct, csched_priv0,
|
||||
csched_priv0->master);
|
||||
|
||||
set_timer( &csched_priv.master_ticker, NOW() +
|
||||
set_timer( &csched_priv0->master_ticker, NOW() +
|
||||
MILLISECS(CSCHED_MSECS_PER_TICK) * CSCHED_TICKS_PER_ACCT );
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(csched_start_tickers);
|
||||
|
||||
static void csched_tick_suspend(void)
|
||||
static void
|
||||
csched_deinit(struct scheduler *ops)
|
||||
{
|
||||
struct csched_private *prv;
|
||||
|
||||
prv = CSCHED_PRIV(ops);
|
||||
if ( prv != NULL )
|
||||
xfree(prv);
|
||||
}
|
||||
|
||||
static void csched_tick_suspend(struct scheduler *ops, unsigned int cpu)
|
||||
{
|
||||
struct csched_pcpu *spc;
|
||||
|
||||
spc = CSCHED_PCPU(smp_processor_id());
|
||||
spc = CSCHED_PCPU(cpu);
|
||||
|
||||
stop_timer(&spc->ticker);
|
||||
}
|
||||
|
||||
static void csched_tick_resume(void)
|
||||
static void csched_tick_resume(struct scheduler *ops, unsigned int cpu)
|
||||
{
|
||||
struct csched_pcpu *spc;
|
||||
uint64_t now = NOW();
|
||||
struct csched_private *prv;
|
||||
|
||||
spc = CSCHED_PCPU(smp_processor_id());
|
||||
prv = CSCHED_PRIV(ops);
|
||||
if ( !prv->ticker_active )
|
||||
return;
|
||||
|
||||
|
||||
spc = CSCHED_PCPU(cpu);
|
||||
|
||||
set_timer(&spc->ticker, now + MILLISECS(CSCHED_MSECS_PER_TICK)
|
||||
- now % MILLISECS(CSCHED_MSECS_PER_TICK) );
|
||||
|
||||
if ( (prv->ticker_active == 2) && (prv->master == cpu) )
|
||||
{
|
||||
set_timer( &prv->master_ticker, now +
|
||||
MILLISECS(CSCHED_MSECS_PER_TICK) * CSCHED_TICKS_PER_ACCT -
|
||||
now % MILLISECS(CSCHED_MSECS_PER_TICK) * CSCHED_TICKS_PER_ACCT);
|
||||
prv->ticker_active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
const struct scheduler sched_credit_def = {
|
||||
static struct csched_private _csched_priv;
|
||||
|
||||
struct scheduler sched_credit_def = {
|
||||
.name = "SMP Credit Scheduler",
|
||||
.opt_name = "credit",
|
||||
.sched_id = XEN_SCHEDULER_CREDIT,
|
||||
.sched_data = &_csched_priv,
|
||||
|
||||
.init_domain = csched_dom_init,
|
||||
.destroy_domain = csched_dom_destroy,
|
||||
|
||||
.init_vcpu = csched_vcpu_init,
|
||||
.insert_vcpu = csched_vcpu_insert,
|
||||
.destroy_vcpu = csched_vcpu_destroy,
|
||||
|
||||
.sleep = csched_vcpu_sleep,
|
||||
@@ -1441,6 +1571,13 @@ const struct scheduler sched_credit_def = {
|
||||
.dump_cpu_state = csched_dump_pcpu,
|
||||
.dump_settings = csched_dump,
|
||||
.init = csched_init,
|
||||
.deinit = csched_deinit,
|
||||
.alloc_vdata = csched_alloc_vdata,
|
||||
.free_vdata = csched_free_vdata,
|
||||
.alloc_pdata = csched_alloc_pdata,
|
||||
.free_pdata = csched_free_pdata,
|
||||
.alloc_domdata = csched_alloc_domdata,
|
||||
.free_domdata = csched_free_domdata,
|
||||
|
||||
.tick_suspend = csched_tick_suspend,
|
||||
.tick_resume = csched_tick_resume,
|
||||
|
||||
+187
-112
@@ -149,12 +149,16 @@
|
||||
/*
|
||||
* Useful macros
|
||||
*/
|
||||
#define CSCHED_PRIV(_ops) \
|
||||
((struct csched_private *)((_ops)->sched_data))
|
||||
#define CSCHED_VCPU(_vcpu) ((struct csched_vcpu *) (_vcpu)->sched_priv)
|
||||
#define CSCHED_DOM(_dom) ((struct csched_dom *) (_dom)->sched_priv)
|
||||
#define CSCHED_CPUONLINE(_pool) \
|
||||
(((_pool) == NULL) ? &cpupool_free_cpus : &(_pool)->cpu_valid)
|
||||
/* CPU to runq_id macro */
|
||||
#define c2r(_cpu) (csched_priv.runq_map[(_cpu)])
|
||||
#define c2r(_ops, _cpu) (CSCHED_PRIV(_ops)->runq_map[(_cpu)])
|
||||
/* CPU to runqueue struct macro */
|
||||
#define RQD(_cpu) (&csched_priv.rqd[c2r(_cpu)])
|
||||
#define RQD(_ops, _cpu) (&CSCHED_PRIV(_ops)->rqd[c2r(_ops, _cpu)])
|
||||
|
||||
/*
|
||||
* Per-runqueue data
|
||||
@@ -213,11 +217,6 @@ struct csched_dom {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
static struct csched_private csched_priv;
|
||||
|
||||
/*
|
||||
* Time-to-credit, credit-to-time.
|
||||
* FIXME: Do pre-calculated division?
|
||||
@@ -284,15 +283,15 @@ __runq_insert(struct list_head *runq, struct csched_vcpu *svc)
|
||||
}
|
||||
|
||||
static void
|
||||
runq_insert(unsigned int cpu, struct csched_vcpu *svc)
|
||||
runq_insert(struct scheduler *ops, unsigned int cpu, struct csched_vcpu *svc)
|
||||
{
|
||||
struct list_head * runq = &RQD(cpu)->runq;
|
||||
struct list_head * runq = &RQD(ops, cpu)->runq;
|
||||
int pos = 0;
|
||||
|
||||
ASSERT( spin_is_locked(per_cpu(schedule_data, cpu).schedule_lock) );
|
||||
|
||||
BUG_ON( __vcpu_on_runq(svc) );
|
||||
BUG_ON( c2r(cpu) != c2r(svc->vcpu->processor) );
|
||||
BUG_ON( c2r(ops, cpu) != c2r(ops, svc->vcpu->processor) );
|
||||
|
||||
pos = __runq_insert(runq, svc);
|
||||
|
||||
@@ -324,11 +323,12 @@ void burn_credits(struct csched_runqueue_data *rqd, struct csched_vcpu *, s_time
|
||||
/* Check to see if the item on the runqueue is higher priority than what's
|
||||
* currently running; if so, wake up the processor */
|
||||
static /*inline*/ void
|
||||
runq_tickle(unsigned int cpu, struct csched_vcpu *new, s_time_t now)
|
||||
runq_tickle(struct scheduler *ops, unsigned int cpu, struct csched_vcpu *new, s_time_t now)
|
||||
{
|
||||
int i, ipid=-1;
|
||||
s_time_t lowest=(1<<30);
|
||||
struct csched_runqueue_data *rqd = RQD(cpu);
|
||||
struct csched_runqueue_data *rqd = RQD(ops, cpu);
|
||||
cpumask_t *online;
|
||||
|
||||
d2printk("rqt d%dv%d cd%dv%d\n",
|
||||
new->vcpu->domain->domain_id,
|
||||
@@ -336,13 +336,14 @@ runq_tickle(unsigned int cpu, struct csched_vcpu *new, s_time_t now)
|
||||
current->domain->domain_id,
|
||||
current->vcpu_id);
|
||||
|
||||
online = CSCHED_CPUONLINE(per_cpu(cpupool, cpu));
|
||||
/* Find the cpu in this queue group that has the lowest credits */
|
||||
for ( i=rqd->cpu_min ; i < rqd->cpu_max ; i++ )
|
||||
{
|
||||
struct csched_vcpu * cur;
|
||||
|
||||
/* Skip cpus that aren't online */
|
||||
if ( !cpu_online(i) )
|
||||
if ( !cpu_isset(i, *online) )
|
||||
continue;
|
||||
|
||||
cur = CSCHED_VCPU(per_cpu(schedule_data, i).curr);
|
||||
@@ -396,11 +397,11 @@ runq_tickle(unsigned int cpu, struct csched_vcpu *new, s_time_t now)
|
||||
/*
|
||||
* Credit-related code
|
||||
*/
|
||||
static void reset_credit(int cpu, s_time_t now)
|
||||
static void reset_credit(struct scheduler *ops, int cpu, s_time_t now)
|
||||
{
|
||||
struct list_head *iter;
|
||||
|
||||
list_for_each( iter, &RQD(cpu)->svc )
|
||||
list_for_each( iter, &RQD(ops, cpu)->svc )
|
||||
{
|
||||
struct csched_vcpu * svc = list_entry(iter, struct csched_vcpu, rqd_elem);
|
||||
|
||||
@@ -521,64 +522,100 @@ __csched_vcpu_check(struct vcpu *vc)
|
||||
#define CSCHED_VCPU_CHECK(_vc)
|
||||
#endif
|
||||
|
||||
static int
|
||||
csched_vcpu_init(struct vcpu *vc)
|
||||
static void *
|
||||
csched_alloc_vdata(struct scheduler *ops, struct vcpu *vc, void *dd)
|
||||
{
|
||||
struct domain * const dom = vc->domain;
|
||||
struct csched_dom *sdom = CSCHED_DOM(dom);
|
||||
struct csched_vcpu *svc;
|
||||
|
||||
printk("%s: Initializing d%dv%d\n",
|
||||
__func__, dom->domain_id, vc->vcpu_id);
|
||||
|
||||
/* Allocate per-VCPU info */
|
||||
svc = xmalloc(struct csched_vcpu);
|
||||
if ( svc == NULL )
|
||||
return -1;
|
||||
return NULL;
|
||||
memset(svc, 0, sizeof(*svc));
|
||||
|
||||
INIT_LIST_HEAD(&svc->rqd_elem);
|
||||
INIT_LIST_HEAD(&svc->sdom_elem);
|
||||
INIT_LIST_HEAD(&svc->runq_elem);
|
||||
|
||||
svc->sdom = sdom;
|
||||
svc->sdom = dd;
|
||||
svc->vcpu = vc;
|
||||
svc->flags = 0U;
|
||||
vc->sched_priv = svc;
|
||||
|
||||
if ( ! is_idle_vcpu(vc) )
|
||||
{
|
||||
BUG_ON( sdom == NULL );
|
||||
BUG_ON( svc->sdom == NULL );
|
||||
|
||||
svc->credit = CSCHED_CREDIT_INIT;
|
||||
svc->weight = sdom->weight;
|
||||
svc->weight = svc->sdom->weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
BUG_ON( svc->sdom != NULL );
|
||||
svc->credit = CSCHED_IDLE_CREDIT;
|
||||
svc->weight = 0;
|
||||
}
|
||||
|
||||
return svc;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_insert(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu *svc = vc->sched_priv;
|
||||
struct domain * const dom = vc->domain;
|
||||
struct csched_dom *sdom = CSCHED_DOM(dom);
|
||||
|
||||
printk("%s: Inserting d%dv%d\n",
|
||||
__func__, dom->domain_id, vc->vcpu_id);
|
||||
|
||||
if ( ! is_idle_vcpu(vc) )
|
||||
{
|
||||
/* FIXME: Do we need the private lock here? */
|
||||
list_add_tail(&svc->sdom_elem, &sdom->vcpu);
|
||||
list_add_tail(&svc->sdom_elem, &svc->sdom->vcpu);
|
||||
|
||||
/* Add vcpu to runqueue of initial processor */
|
||||
/* FIXME: Abstract for multiple runqueues */
|
||||
vcpu_schedule_lock_irq(vc);
|
||||
|
||||
list_add_tail(&svc->rqd_elem, &RQD(vc->processor)->svc);
|
||||
update_max_weight(RQD(vc->processor), svc->weight, 0);
|
||||
list_add_tail(&svc->rqd_elem, &RQD(ops, vc->processor)->svc);
|
||||
update_max_weight(RQD(ops, vc->processor), svc->weight, 0);
|
||||
|
||||
vcpu_schedule_unlock_irq(vc);
|
||||
|
||||
sdom->nr_vcpus++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BUG_ON( sdom != NULL );
|
||||
svc->credit = CSCHED_IDLE_CREDIT;
|
||||
svc->weight = 0;
|
||||
}
|
||||
|
||||
CSCHED_VCPU_CHECK(vc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_destroy(struct vcpu *vc)
|
||||
csched_free_vdata(struct scheduler *ops, void *priv)
|
||||
{
|
||||
struct csched_vcpu *svc = priv;
|
||||
struct vcpu *vc = svc->vcpu;
|
||||
|
||||
if ( ! is_idle_vcpu(vc) )
|
||||
{
|
||||
/* Remove from runqueue */
|
||||
vcpu_schedule_lock_irq(vc);
|
||||
|
||||
list_del_init(&svc->rqd_elem);
|
||||
update_max_weight(RQD(ops, vc->processor), 0, svc->weight);
|
||||
|
||||
vcpu_schedule_unlock_irq(vc);
|
||||
|
||||
/* Remove from sdom list. Don't need a lock for this, as it's called
|
||||
* syncronously when nothing else can happen. */
|
||||
list_del_init(&svc->sdom_elem);
|
||||
|
||||
svc->sdom->nr_vcpus--;
|
||||
}
|
||||
|
||||
xfree(svc);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_destroy(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
struct csched_dom * const sdom = svc->sdom;
|
||||
@@ -586,25 +623,11 @@ csched_vcpu_destroy(struct vcpu *vc)
|
||||
BUG_ON( sdom == NULL );
|
||||
BUG_ON( !list_empty(&svc->runq_elem) );
|
||||
|
||||
/* Remove from runqueue */
|
||||
vcpu_schedule_lock_irq(vc);
|
||||
|
||||
list_del_init(&svc->rqd_elem);
|
||||
update_max_weight(RQD(vc->processor), 0, svc->weight);
|
||||
|
||||
vcpu_schedule_unlock_irq(vc);
|
||||
|
||||
/* Remove from sdom list. Don't need a lock for this, as it's called
|
||||
* syncronously when nothing else can happen. */
|
||||
list_del_init(&svc->sdom_elem);
|
||||
|
||||
sdom->nr_vcpus--;
|
||||
|
||||
xfree(svc);
|
||||
csched_free_vdata(ops, svc);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_sleep(struct vcpu *vc)
|
||||
csched_vcpu_sleep(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
|
||||
@@ -617,7 +640,7 @@ csched_vcpu_sleep(struct vcpu *vc)
|
||||
}
|
||||
|
||||
static void
|
||||
csched_vcpu_wake(struct vcpu *vc)
|
||||
csched_vcpu_wake(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
const unsigned int cpu = vc->processor;
|
||||
@@ -654,8 +677,8 @@ csched_vcpu_wake(struct vcpu *vc)
|
||||
now = NOW();
|
||||
|
||||
/* Put the VCPU on the runq */
|
||||
runq_insert(cpu, svc);
|
||||
runq_tickle(cpu, svc, now);
|
||||
runq_insert(ops, cpu, svc);
|
||||
runq_tickle(ops, cpu, svc, now);
|
||||
|
||||
out:
|
||||
d2printk("w-\n");
|
||||
@@ -663,7 +686,7 @@ out:
|
||||
}
|
||||
|
||||
static void
|
||||
csched_context_saved(struct vcpu *vc)
|
||||
csched_context_saved(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
|
||||
|
||||
@@ -688,15 +711,15 @@ csched_context_saved(struct vcpu *vc)
|
||||
|
||||
BUG_ON(__vcpu_on_runq(svc));
|
||||
|
||||
runq_insert(cpu, svc);
|
||||
runq_tickle(cpu, svc, NOW());
|
||||
runq_insert(ops, cpu, svc);
|
||||
runq_tickle(ops, cpu, svc, NOW());
|
||||
}
|
||||
|
||||
vcpu_schedule_unlock_irq(vc);
|
||||
}
|
||||
|
||||
static int
|
||||
csched_cpu_pick(struct vcpu *vc)
|
||||
csched_cpu_pick(struct scheduler *ops, struct vcpu *vc)
|
||||
{
|
||||
/* FIXME: Chose a schedule group based on load */
|
||||
/* FIXME: Migrate the vcpu to the new runqueue list, updating
|
||||
@@ -706,10 +729,12 @@ csched_cpu_pick(struct vcpu *vc)
|
||||
|
||||
static int
|
||||
csched_dom_cntl(
|
||||
struct scheduler *ops,
|
||||
struct domain *d,
|
||||
struct xen_domctl_scheduler_op *op)
|
||||
{
|
||||
struct csched_dom * const sdom = CSCHED_DOM(d);
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
unsigned long flags;
|
||||
|
||||
if ( op->cmd == XEN_DOMCTL_SCHEDOP_getinfo )
|
||||
@@ -727,7 +752,7 @@ csched_dom_cntl(
|
||||
|
||||
/* Must hold csched_priv lock to update sdom, runq lock to
|
||||
* update csvcs. */
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
spin_lock_irqsave(&prv->lock, flags);
|
||||
|
||||
old_weight = sdom->weight;
|
||||
|
||||
@@ -744,32 +769,28 @@ csched_dom_cntl(
|
||||
vcpu_schedule_lock_irq(svc->vcpu);
|
||||
|
||||
svc->weight = sdom->weight;
|
||||
update_max_weight(RQD(svc->vcpu->processor), svc->weight, old_weight);
|
||||
update_max_weight(RQD(ops, svc->vcpu->processor), svc->weight, old_weight);
|
||||
|
||||
vcpu_schedule_unlock_irq(svc->vcpu);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
spin_unlock_irqrestore(&prv->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
csched_dom_init(struct domain *dom)
|
||||
static void *
|
||||
csched_alloc_domdata(struct scheduler *ops, struct domain *dom)
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
int flags;
|
||||
|
||||
printk("%s: Initializing domain %d\n", __func__, dom->domain_id);
|
||||
|
||||
if ( is_idle_domain(dom) )
|
||||
return 0;
|
||||
|
||||
sdom = xmalloc(struct csched_dom);
|
||||
if ( sdom == NULL )
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
memset(sdom, 0, sizeof(*sdom));
|
||||
|
||||
/* Initialize credit and weight */
|
||||
INIT_LIST_HEAD(&sdom->vcpu);
|
||||
@@ -778,40 +799,65 @@ csched_dom_init(struct domain *dom)
|
||||
sdom->weight = CSCHED_DEFAULT_WEIGHT;
|
||||
sdom->nr_vcpus = 0;
|
||||
|
||||
spin_lock_irqsave(&CSCHED_PRIV(ops)->lock, flags);
|
||||
|
||||
list_add_tail(&sdom->sdom_elem, &CSCHED_PRIV(ops)->sdom);
|
||||
|
||||
spin_unlock_irqrestore(&CSCHED_PRIV(ops)->lock, flags);
|
||||
|
||||
return (void *)sdom;
|
||||
}
|
||||
|
||||
static int
|
||||
csched_dom_init(struct scheduler *ops, struct domain *dom)
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
|
||||
printk("%s: Initializing domain %d\n", __func__, dom->domain_id);
|
||||
|
||||
if ( is_idle_domain(dom) )
|
||||
return 0;
|
||||
|
||||
sdom = csched_alloc_domdata(ops, dom);
|
||||
if ( sdom == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
dom->sched_priv = sdom;
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
|
||||
list_add_tail(&sdom->sdom_elem, &csched_priv.sdom);
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dom_destroy(struct domain *dom)
|
||||
csched_free_domdata(struct scheduler *ops, void *data)
|
||||
{
|
||||
struct csched_dom *sdom = CSCHED_DOM(dom);
|
||||
int flags;
|
||||
struct csched_dom *sdom = data;
|
||||
|
||||
BUG_ON(!list_empty(&sdom->vcpu));
|
||||
|
||||
spin_lock_irqsave(&csched_priv.lock, flags);
|
||||
spin_lock_irqsave(&CSCHED_PRIV(ops)->lock, flags);
|
||||
|
||||
list_del_init(&sdom->sdom_elem);
|
||||
|
||||
spin_unlock_irqrestore(&csched_priv.lock, flags);
|
||||
spin_unlock_irqrestore(&CSCHED_PRIV(ops)->lock, flags);
|
||||
|
||||
xfree(CSCHED_DOM(dom));
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dom_destroy(struct scheduler *ops, struct domain *dom)
|
||||
{
|
||||
struct csched_dom *sdom = CSCHED_DOM(dom);
|
||||
|
||||
BUG_ON(!list_empty(&sdom->vcpu));
|
||||
|
||||
csched_free_domdata(ops, CSCHED_DOM(dom));
|
||||
}
|
||||
|
||||
/* How long should we let this vcpu run for? */
|
||||
static s_time_t
|
||||
csched_runtime(int cpu, struct csched_vcpu *snext)
|
||||
csched_runtime(struct scheduler *ops, int cpu, struct csched_vcpu *snext)
|
||||
{
|
||||
s_time_t time = CSCHED_MAX_TIMER;
|
||||
struct csched_runqueue_data *rqd = RQD(cpu);
|
||||
struct csched_runqueue_data *rqd = RQD(ops, cpu);
|
||||
struct list_head *runq = &rqd->runq;
|
||||
|
||||
if ( is_idle_vcpu(snext->vcpu) )
|
||||
@@ -851,10 +897,10 @@ void __dump_execstate(void *unused);
|
||||
* fast for the common case.
|
||||
*/
|
||||
static struct task_slice
|
||||
csched_schedule(s_time_t now)
|
||||
csched_schedule(struct scheduler *ops, s_time_t now)
|
||||
{
|
||||
const int cpu = smp_processor_id();
|
||||
struct csched_runqueue_data *rqd = RQD(cpu);
|
||||
struct csched_runqueue_data *rqd = RQD(ops, cpu);
|
||||
struct list_head * const runq = &rqd->runq;
|
||||
struct csched_vcpu * const scurr = CSCHED_VCPU(current);
|
||||
struct csched_vcpu *snext = NULL;
|
||||
@@ -927,7 +973,7 @@ csched_schedule(s_time_t now)
|
||||
}
|
||||
|
||||
if ( !is_idle_vcpu(snext->vcpu) && snext->credit <= CSCHED_CREDIT_RESET )
|
||||
reset_credit(cpu, now);
|
||||
reset_credit(ops, cpu, now);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
@@ -955,7 +1001,7 @@ csched_schedule(s_time_t now)
|
||||
/*
|
||||
* Return task to run next...
|
||||
*/
|
||||
ret.time = csched_runtime(cpu, snext);
|
||||
ret.time = csched_runtime(ops, cpu, snext);
|
||||
ret.task = snext->vcpu;
|
||||
|
||||
CSCHED_VCPU_CHECK(ret.task);
|
||||
@@ -977,7 +1023,7 @@ csched_dump_vcpu(struct csched_vcpu *svc)
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dump_pcpu(int cpu)
|
||||
csched_dump_pcpu(struct scheduler *ops, int cpu)
|
||||
{
|
||||
struct list_head *runq, *iter;
|
||||
struct csched_vcpu *svc;
|
||||
@@ -986,7 +1032,7 @@ csched_dump_pcpu(int cpu)
|
||||
|
||||
/* FIXME: Do locking properly for access to runqueue structures */
|
||||
|
||||
runq = &RQD(cpu)->runq;
|
||||
runq = &RQD(ops, cpu)->runq;
|
||||
|
||||
cpumask_scnprintf(cpustr, sizeof(cpustr), per_cpu(cpu_sibling_map,cpu));
|
||||
printk(" sibling=%s, ", cpustr);
|
||||
@@ -1014,22 +1060,23 @@ csched_dump_pcpu(int cpu)
|
||||
}
|
||||
|
||||
static void
|
||||
csched_dump(void)
|
||||
csched_dump(struct scheduler *ops)
|
||||
{
|
||||
struct list_head *iter_sdom, *iter_svc;
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
int loop;
|
||||
|
||||
printk("info:\n"
|
||||
"\tncpus = %u\n"
|
||||
"\tdefault-weight = %d\n",
|
||||
csched_priv.ncpus,
|
||||
prv->ncpus,
|
||||
CSCHED_DEFAULT_WEIGHT);
|
||||
|
||||
/* FIXME: Locking! */
|
||||
|
||||
printk("active vcpus:\n");
|
||||
loop = 0;
|
||||
list_for_each( iter_sdom, &csched_priv.sdom )
|
||||
list_for_each( iter_sdom, &prv->sdom )
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
sdom = list_entry(iter_sdom, struct csched_dom, sdom_elem);
|
||||
@@ -1046,42 +1093,49 @@ csched_dump(void)
|
||||
}
|
||||
|
||||
static void
|
||||
make_runq_map(void)
|
||||
make_runq_map(struct scheduler *ops)
|
||||
{
|
||||
int cpu, cpu_count=0;
|
||||
struct csched_private *prv = CSCHED_PRIV(ops);
|
||||
|
||||
/* FIXME: Read pcpu layout and do this properly */
|
||||
for_each_possible_cpu( cpu )
|
||||
{
|
||||
csched_priv.runq_map[cpu] = 0;
|
||||
prv->runq_map[cpu] = 0;
|
||||
cpu_count++;
|
||||
}
|
||||
csched_priv.runq_count = 1;
|
||||
prv->runq_count = 1;
|
||||
|
||||
/* Move to the init code...? */
|
||||
csched_priv.rqd[0].cpu_min = 0;
|
||||
csched_priv.rqd[0].cpu_max = cpu_count;
|
||||
prv->rqd[0].cpu_min = 0;
|
||||
prv->rqd[0].cpu_max = cpu_count;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_init(void)
|
||||
static int
|
||||
csched_init(struct scheduler *ops, int pool0)
|
||||
{
|
||||
int i;
|
||||
struct csched_private *prv;
|
||||
|
||||
printk("Initializing Credit2 scheduler\n" \
|
||||
" WARNING: This is experimental software in development.\n" \
|
||||
" Use at your own risk.\n");
|
||||
|
||||
spin_lock_init(&csched_priv.lock);
|
||||
INIT_LIST_HEAD(&csched_priv.sdom);
|
||||
prv = xmalloc(struct csched_private);
|
||||
if ( prv == NULL )
|
||||
return 1;
|
||||
memset(prv, 0, sizeof(*prv));
|
||||
|
||||
csched_priv.ncpus = 0;
|
||||
spin_lock_init(&prv->lock);
|
||||
INIT_LIST_HEAD(&prv->sdom);
|
||||
|
||||
make_runq_map();
|
||||
prv->ncpus = 0;
|
||||
|
||||
for ( i=0; i<csched_priv.runq_count ; i++ )
|
||||
make_runq_map(ops);
|
||||
|
||||
for ( i=0; i<prv->runq_count ; i++ )
|
||||
{
|
||||
struct csched_runqueue_data *rqd = csched_priv.rqd + i;
|
||||
struct csched_runqueue_data *rqd = prv->rqd + i;
|
||||
|
||||
rqd->max_weight = 1;
|
||||
rqd->id = i;
|
||||
@@ -1096,24 +1150,40 @@ csched_init(void)
|
||||
spinlock_t *lock;
|
||||
|
||||
/* Point the per-cpu schedule lock to the runq_id lock */
|
||||
runq_id = csched_priv.runq_map[i];
|
||||
runq_id = prv->runq_map[i];
|
||||
lock = &per_cpu(schedule_data, runq_id)._lock;
|
||||
|
||||
per_cpu(schedule_data, i).schedule_lock = lock;
|
||||
|
||||
csched_priv.ncpus++;
|
||||
prv->ncpus++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
csched_deinit(struct scheduler *ops)
|
||||
{
|
||||
struct csched_private *prv;
|
||||
|
||||
prv = CSCHED_PRIV(ops);
|
||||
if ( prv != NULL )
|
||||
xfree(prv);
|
||||
}
|
||||
|
||||
|
||||
static struct csched_private _csched_priv;
|
||||
|
||||
struct scheduler sched_credit2_def = {
|
||||
.name = "SMP Credit Scheduler rev2",
|
||||
.opt_name = "credit2",
|
||||
.sched_id = XEN_SCHEDULER_CREDIT2,
|
||||
.sched_data = &_csched_priv,
|
||||
|
||||
.init_domain = csched_dom_init,
|
||||
.destroy_domain = csched_dom_destroy,
|
||||
|
||||
.init_vcpu = csched_vcpu_init,
|
||||
.insert_vcpu = csched_vcpu_insert,
|
||||
.destroy_vcpu = csched_vcpu_destroy,
|
||||
|
||||
.sleep = csched_vcpu_sleep,
|
||||
@@ -1128,4 +1198,9 @@ struct scheduler sched_credit2_def = {
|
||||
.dump_cpu_state = csched_dump_pcpu,
|
||||
.dump_settings = csched_dump,
|
||||
.init = csched_init,
|
||||
.deinit = csched_deinit,
|
||||
.alloc_vdata = csched_alloc_vdata,
|
||||
.free_vdata = csched_free_vdata,
|
||||
.alloc_domdata = csched_alloc_domdata,
|
||||
.free_domdata = csched_free_domdata,
|
||||
};
|
||||
+98
-46
@@ -21,6 +21,9 @@
|
||||
printk(_a ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define SEDF_CPUONLINE(_pool) \
|
||||
(((_pool) == NULL) ? &cpupool_free_cpus : &(_pool)->cpu_valid)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define SEDF_STATS
|
||||
#define CHECK(_p) \
|
||||
@@ -132,7 +135,7 @@ struct sedf_cpu_info {
|
||||
#define sedf_runnable(edom) (!(EDOM_INFO(edom)->status & SEDF_ASLEEP))
|
||||
|
||||
|
||||
static void sedf_dump_cpu_state(int i);
|
||||
static void sedf_dump_cpu_state(struct scheduler *ops, int i);
|
||||
|
||||
static inline int extraq_on(struct vcpu *d, int i)
|
||||
{
|
||||
@@ -329,30 +332,17 @@ static inline void __add_to_runqueue_sort(struct vcpu *v)
|
||||
}
|
||||
|
||||
|
||||
static int sedf_init_vcpu(struct vcpu *v)
|
||||
static void *sedf_alloc_vdata(struct scheduler *ops, struct vcpu *v, void *dd)
|
||||
{
|
||||
struct sedf_vcpu_info *inf;
|
||||
|
||||
if ( (v->sched_priv = xmalloc(struct sedf_vcpu_info)) == NULL )
|
||||
return -1;
|
||||
memset(v->sched_priv, 0, sizeof(struct sedf_vcpu_info));
|
||||
inf = xmalloc(struct sedf_vcpu_info);
|
||||
if ( inf == NULL )
|
||||
return NULL;
|
||||
|
||||
inf = EDOM_INFO(v);
|
||||
memset(inf, 0, sizeof(struct sedf_vcpu_info));
|
||||
inf->vcpu = v;
|
||||
|
||||
/* Allocate per-CPU context if this is the first domain to be added. */
|
||||
if ( unlikely(per_cpu(schedule_data, v->processor).sched_priv == NULL) )
|
||||
{
|
||||
per_cpu(schedule_data, v->processor).sched_priv =
|
||||
xmalloc(struct sedf_cpu_info);
|
||||
BUG_ON(per_cpu(schedule_data, v->processor).sched_priv == NULL);
|
||||
memset(CPU_INFO(v->processor), 0, sizeof(*CPU_INFO(v->processor)));
|
||||
INIT_LIST_HEAD(WAITQ(v->processor));
|
||||
INIT_LIST_HEAD(RUNQ(v->processor));
|
||||
INIT_LIST_HEAD(EXTRAQ(v->processor,EXTRA_PEN_Q));
|
||||
INIT_LIST_HEAD(EXTRAQ(v->processor,EXTRA_UTIL_Q));
|
||||
}
|
||||
|
||||
|
||||
/* Every VCPU gets an equal share of extratime by default. */
|
||||
inf->deadl_abs = 0;
|
||||
inf->latency = 0;
|
||||
@@ -383,39 +373,88 @@ static int sedf_init_vcpu(struct vcpu *v)
|
||||
}
|
||||
else
|
||||
{
|
||||
EDOM_INFO(v)->deadl_abs = 0;
|
||||
EDOM_INFO(v)->status &= ~SEDF_ASLEEP;
|
||||
inf->deadl_abs = 0;
|
||||
inf->status &= ~SEDF_ASLEEP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return inf;
|
||||
}
|
||||
|
||||
static void sedf_destroy_vcpu(struct vcpu *v)
|
||||
static void *
|
||||
sedf_alloc_pdata(struct scheduler *ops, int cpu)
|
||||
{
|
||||
xfree(v->sched_priv);
|
||||
struct sedf_cpu_info *spc;
|
||||
|
||||
spc = xmalloc(struct sedf_cpu_info);
|
||||
BUG_ON(spc == NULL);
|
||||
memset(spc, 0, sizeof(*spc));
|
||||
INIT_LIST_HEAD(&spc->waitq);
|
||||
INIT_LIST_HEAD(&spc->runnableq);
|
||||
INIT_LIST_HEAD(&spc->extraq[EXTRA_PEN_Q]);
|
||||
INIT_LIST_HEAD(&spc->extraq[EXTRA_UTIL_Q]);
|
||||
|
||||
return (void *)spc;
|
||||
}
|
||||
|
||||
static int sedf_init_domain(struct domain *d)
|
||||
static void
|
||||
sedf_free_pdata(struct scheduler *ops, void *spc, int cpu)
|
||||
{
|
||||
d->sched_priv = xmalloc(struct sedf_dom_info);
|
||||
if ( spc == NULL )
|
||||
return;
|
||||
|
||||
xfree(spc);
|
||||
}
|
||||
|
||||
static void sedf_free_vdata(struct scheduler *ops, void *priv)
|
||||
{
|
||||
xfree(priv);
|
||||
}
|
||||
|
||||
static void sedf_destroy_vcpu(struct scheduler *ops, struct vcpu *v)
|
||||
{
|
||||
sedf_free_vdata(ops, v->sched_priv);
|
||||
}
|
||||
|
||||
static void *
|
||||
sedf_alloc_domdata(struct scheduler *ops, struct domain *d)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
mem = xmalloc(struct sedf_dom_info);
|
||||
if ( mem == NULL )
|
||||
return NULL;
|
||||
|
||||
memset(mem, 0, sizeof(struct sedf_dom_info));
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
static int sedf_init_domain(struct scheduler *ops, struct domain *d)
|
||||
{
|
||||
d->sched_priv = sedf_alloc_domdata(ops, d);
|
||||
if ( d->sched_priv == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
memset(d->sched_priv, 0, sizeof(struct sedf_dom_info));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sedf_destroy_domain(struct domain *d)
|
||||
static void sedf_free_domdata(struct scheduler *ops, void *data)
|
||||
{
|
||||
xfree(d->sched_priv);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
static int sedf_pick_cpu(struct vcpu *v)
|
||||
static void sedf_destroy_domain(struct scheduler *ops, struct domain *d)
|
||||
{
|
||||
sedf_free_domdata(ops, d->sched_priv);
|
||||
}
|
||||
|
||||
static int sedf_pick_cpu(struct scheduler *ops, struct vcpu *v)
|
||||
{
|
||||
cpumask_t online_affinity;
|
||||
cpumask_t *online;
|
||||
|
||||
cpus_and(online_affinity, v->cpu_affinity, cpu_online_map);
|
||||
online = SEDF_CPUONLINE(v->domain->cpupool);
|
||||
cpus_and(online_affinity, v->cpu_affinity, *online);
|
||||
return first_cpu(online_affinity);
|
||||
}
|
||||
|
||||
@@ -751,7 +790,7 @@ static struct task_slice sedf_do_extra_schedule(
|
||||
-timeslice for the current period used up
|
||||
-domain on waitqueue has started it's period
|
||||
-and various others ;) in general: determine which domain to run next*/
|
||||
static struct task_slice sedf_do_schedule(s_time_t now)
|
||||
static struct task_slice sedf_do_schedule(struct scheduler *ops, s_time_t now)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct list_head *runq = RUNQ(cpu);
|
||||
@@ -786,6 +825,13 @@ static struct task_slice sedf_do_schedule(s_time_t now)
|
||||
}
|
||||
check_waitq:
|
||||
update_queues(now, runq, waitq);
|
||||
|
||||
if ( unlikely(!cpu_isset(cpu, *SEDF_CPUONLINE(per_cpu(cpupool, cpu)))) )
|
||||
{
|
||||
ret.task = IDLETASK(cpu);
|
||||
ret.time = SECONDS(1);
|
||||
goto sched_done;
|
||||
}
|
||||
|
||||
/*now simply pick the first domain from the runqueue, which has the
|
||||
earliest deadline, because the list is sorted*/
|
||||
@@ -824,6 +870,7 @@ static struct task_slice sedf_do_schedule(s_time_t now)
|
||||
extraq, cpu);
|
||||
}
|
||||
|
||||
sched_done:
|
||||
/*TODO: Do something USEFUL when this happens and find out, why it
|
||||
still can happen!!!*/
|
||||
if ( ret.time < 0)
|
||||
@@ -841,7 +888,7 @@ static struct task_slice sedf_do_schedule(s_time_t now)
|
||||
}
|
||||
|
||||
|
||||
static void sedf_sleep(struct vcpu *d)
|
||||
static void sedf_sleep(struct scheduler *ops, struct vcpu *d)
|
||||
{
|
||||
PRINT(2,"sedf_sleep was called, domain-id %i.%i\n",
|
||||
d->domain->domain_id, d->vcpu_id);
|
||||
@@ -1060,7 +1107,7 @@ static inline int should_switch(struct vcpu *cur,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sedf_wake(struct vcpu *d)
|
||||
static void sedf_wake(struct scheduler *ops, struct vcpu *d)
|
||||
{
|
||||
s_time_t now = NOW();
|
||||
struct sedf_vcpu_info* inf = EDOM_INFO(d);
|
||||
@@ -1213,8 +1260,8 @@ static void sedf_dump_domain(struct vcpu *d)
|
||||
}
|
||||
|
||||
|
||||
/* dumps all domains on hte specified cpu */
|
||||
static void sedf_dump_cpu_state(int i)
|
||||
/* dumps all domains on the specified cpu */
|
||||
static void sedf_dump_cpu_state(struct scheduler *ops, int i)
|
||||
{
|
||||
struct list_head *list, *queue, *tmp;
|
||||
struct sedf_vcpu_info *d_inf;
|
||||
@@ -1287,7 +1334,7 @@ static void sedf_dump_cpu_state(int i)
|
||||
|
||||
|
||||
/* Adjusts periods and slices of the domains accordingly to their weights. */
|
||||
static int sedf_adjust_weights(struct xen_domctl_scheduler_op *cmd)
|
||||
static int sedf_adjust_weights(struct cpupool *c, struct xen_domctl_scheduler_op *cmd)
|
||||
{
|
||||
struct vcpu *p;
|
||||
struct domain *d;
|
||||
@@ -1308,6 +1355,8 @@ static int sedf_adjust_weights(struct xen_domctl_scheduler_op *cmd)
|
||||
rcu_read_lock(&domlist_read_lock);
|
||||
for_each_domain( d )
|
||||
{
|
||||
if ( c != d->cpupool )
|
||||
continue;
|
||||
for_each_vcpu( d, p )
|
||||
{
|
||||
if ( EDOM_INFO(p)->weight )
|
||||
@@ -1359,7 +1408,7 @@ static int sedf_adjust_weights(struct xen_domctl_scheduler_op *cmd)
|
||||
|
||||
|
||||
/* set or fetch domain scheduling parameters */
|
||||
static int sedf_adjust(struct domain *p, struct xen_domctl_scheduler_op *op)
|
||||
static int sedf_adjust(struct scheduler *ops, struct domain *p, struct xen_domctl_scheduler_op *op)
|
||||
{
|
||||
struct vcpu *v;
|
||||
int rc;
|
||||
@@ -1369,9 +1418,6 @@ static int sedf_adjust(struct domain *p, struct xen_domctl_scheduler_op *op)
|
||||
p->domain_id, op->u.sedf.period, op->u.sedf.slice,
|
||||
op->u.sedf.latency, (op->u.sedf.extratime)?"yes":"no");
|
||||
|
||||
if ( !p->vcpu )
|
||||
return -EINVAL;
|
||||
|
||||
if ( op->cmd == XEN_DOMCTL_SCHEDOP_putinfo )
|
||||
{
|
||||
/* Check for sane parameters. */
|
||||
@@ -1421,7 +1467,7 @@ static int sedf_adjust(struct domain *p, struct xen_domctl_scheduler_op *op)
|
||||
}
|
||||
}
|
||||
|
||||
rc = sedf_adjust_weights(op);
|
||||
rc = sedf_adjust_weights(p->cpupool, op);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
@@ -1449,7 +1495,7 @@ static int sedf_adjust(struct domain *p, struct xen_domctl_scheduler_op *op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct scheduler sched_sedf_def = {
|
||||
struct scheduler sched_sedf_def = {
|
||||
.name = "Simple EDF Scheduler",
|
||||
.opt_name = "sedf",
|
||||
.sched_id = XEN_SCHEDULER_SEDF,
|
||||
@@ -1457,9 +1503,15 @@ const struct scheduler sched_sedf_def = {
|
||||
.init_domain = sedf_init_domain,
|
||||
.destroy_domain = sedf_destroy_domain,
|
||||
|
||||
.init_vcpu = sedf_init_vcpu,
|
||||
.destroy_vcpu = sedf_destroy_vcpu,
|
||||
|
||||
.alloc_vdata = sedf_alloc_vdata,
|
||||
.free_vdata = sedf_free_vdata,
|
||||
.alloc_pdata = sedf_alloc_pdata,
|
||||
.free_pdata = sedf_free_pdata,
|
||||
.alloc_domdata = sedf_alloc_domdata,
|
||||
.free_domdata = sedf_free_domdata,
|
||||
|
||||
.do_schedule = sedf_do_schedule,
|
||||
.pick_cpu = sedf_pick_cpu,
|
||||
.dump_cpu_state = sedf_dump_cpu_state,
|
||||
|
||||
+254
-46
@@ -53,11 +53,12 @@ static void poll_timer_fn(void *data);
|
||||
|
||||
/* This is global for now so that private implementations can reach it */
|
||||
DEFINE_PER_CPU(struct schedule_data, schedule_data);
|
||||
DEFINE_PER_CPU(struct scheduler *, scheduler);
|
||||
|
||||
extern const struct scheduler sched_sedf_def;
|
||||
extern const struct scheduler sched_credit_def;
|
||||
extern const struct scheduler sched_credit2_def;
|
||||
static const struct scheduler *__initdata schedulers[] = {
|
||||
static const struct scheduler *schedulers[] = {
|
||||
&sched_sedf_def,
|
||||
&sched_credit_def,
|
||||
&sched_credit2_def,
|
||||
@@ -66,9 +67,15 @@ static const struct scheduler *__initdata schedulers[] = {
|
||||
|
||||
static struct scheduler __read_mostly ops;
|
||||
|
||||
#define SCHED_OP(fn, ...) \
|
||||
(( ops.fn != NULL ) ? ops.fn( __VA_ARGS__ ) \
|
||||
: (typeof(ops.fn(__VA_ARGS__)))0 )
|
||||
#define SCHED_OP(opsptr, fn, ...) \
|
||||
(( (opsptr)->fn != NULL ) ? (opsptr)->fn(opsptr, ##__VA_ARGS__ ) \
|
||||
: (typeof((opsptr)->fn(opsptr, ##__VA_ARGS__)))0 )
|
||||
|
||||
#define DOM2OP(_d) (((_d)->cpupool == NULL) ? &ops : &((_d)->cpupool->sched))
|
||||
#define VCPU2OP(_v) (DOM2OP((_v)->domain))
|
||||
#define VCPU2ONLINE(_v) \
|
||||
(((_v)->domain->cpupool == NULL) ? &cpu_online_map \
|
||||
: &(_v)->domain->cpupool->cpu_valid)
|
||||
|
||||
static inline void trace_runstate_change(struct vcpu *v, int new_state)
|
||||
{
|
||||
@@ -209,7 +216,86 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor)
|
||||
|
||||
TRACE_2D(TRC_SCHED_DOM_ADD, v->domain->domain_id, v->vcpu_id);
|
||||
|
||||
return SCHED_OP(init_vcpu, v);
|
||||
if ( unlikely(per_cpu(schedule_data, v->processor).sched_priv == NULL) )
|
||||
{
|
||||
per_cpu(schedule_data, v->processor).sched_priv =
|
||||
SCHED_OP(DOM2OP(d), alloc_pdata, processor);
|
||||
if ( per_cpu(schedule_data, v->processor).sched_priv == NULL )
|
||||
return 1;
|
||||
}
|
||||
|
||||
v->sched_priv = SCHED_OP(DOM2OP(d), alloc_vdata, v, d->sched_priv);
|
||||
if ( v->sched_priv == NULL )
|
||||
return 1;
|
||||
|
||||
if ( is_idle_domain(d) )
|
||||
per_cpu(schedule_data, v->processor).sched_idlevpriv = v->sched_priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_move_domain(struct domain *d, struct cpupool *c)
|
||||
{
|
||||
struct vcpu *v;
|
||||
unsigned int new_p;
|
||||
void **vcpu_priv;
|
||||
void *domdata;
|
||||
|
||||
domdata = SCHED_OP(&(c->sched), alloc_domdata, d);
|
||||
if ( domdata == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
vcpu_priv = xmalloc_array(void *, d->max_vcpus);
|
||||
if ( vcpu_priv == NULL )
|
||||
{
|
||||
SCHED_OP(&(c->sched), free_domdata, domdata);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(vcpu_priv, 0, d->max_vcpus * sizeof(void *));
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
vcpu_priv[v->vcpu_id] = SCHED_OP(&(c->sched), alloc_vdata, v, domdata);
|
||||
if ( vcpu_priv[v->vcpu_id] == NULL )
|
||||
{
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
if ( vcpu_priv[v->vcpu_id] != NULL )
|
||||
xfree(vcpu_priv[v->vcpu_id]);
|
||||
}
|
||||
xfree(vcpu_priv);
|
||||
SCHED_OP(&(c->sched), free_domdata, domdata);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
domain_pause(d);
|
||||
|
||||
new_p = first_cpu(c->cpu_valid);
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
migrate_timer(&v->periodic_timer, new_p);
|
||||
migrate_timer(&v->singleshot_timer, new_p);
|
||||
migrate_timer(&v->poll_timer, new_p);
|
||||
|
||||
SCHED_OP(VCPU2OP(v), destroy_vcpu, v);
|
||||
|
||||
cpus_setall(v->cpu_affinity);
|
||||
v->processor = new_p;
|
||||
v->sched_priv = vcpu_priv[v->vcpu_id];
|
||||
|
||||
new_p = cycle_cpu(new_p, c->cpu_valid);
|
||||
}
|
||||
|
||||
d->cpupool = c;
|
||||
SCHED_OP(DOM2OP(d), free_domdata, d->sched_priv);
|
||||
d->sched_priv = domdata;
|
||||
|
||||
domain_unpause(d);
|
||||
|
||||
xfree(vcpu_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sched_destroy_vcpu(struct vcpu *v)
|
||||
@@ -219,17 +305,17 @@ void sched_destroy_vcpu(struct vcpu *v)
|
||||
kill_timer(&v->poll_timer);
|
||||
if ( test_and_clear_bool(v->is_urgent) )
|
||||
atomic_dec(&per_cpu(schedule_data, v->processor).urgent_count);
|
||||
SCHED_OP(destroy_vcpu, v);
|
||||
SCHED_OP(VCPU2OP(v), destroy_vcpu, v);
|
||||
}
|
||||
|
||||
int sched_init_domain(struct domain *d)
|
||||
{
|
||||
return SCHED_OP(init_domain, d);
|
||||
return SCHED_OP(DOM2OP(d), init_domain, d);
|
||||
}
|
||||
|
||||
void sched_destroy_domain(struct domain *d)
|
||||
{
|
||||
SCHED_OP(destroy_domain, d);
|
||||
SCHED_OP(DOM2OP(d), destroy_domain, d);
|
||||
}
|
||||
|
||||
void vcpu_sleep_nosync(struct vcpu *v)
|
||||
@@ -243,7 +329,7 @@ void vcpu_sleep_nosync(struct vcpu *v)
|
||||
if ( v->runstate.state == RUNSTATE_runnable )
|
||||
vcpu_runstate_change(v, RUNSTATE_offline, NOW());
|
||||
|
||||
SCHED_OP(sleep, v);
|
||||
SCHED_OP(VCPU2OP(v), sleep, v);
|
||||
}
|
||||
|
||||
vcpu_schedule_unlock_irqrestore(v, flags);
|
||||
@@ -271,7 +357,7 @@ void vcpu_wake(struct vcpu *v)
|
||||
{
|
||||
if ( v->runstate.state >= RUNSTATE_blocked )
|
||||
vcpu_runstate_change(v, RUNSTATE_runnable, NOW());
|
||||
SCHED_OP(wake, v);
|
||||
SCHED_OP(VCPU2OP(v), wake, v);
|
||||
}
|
||||
else if ( !test_bit(_VPF_blocked, &v->pause_flags) )
|
||||
{
|
||||
@@ -326,7 +412,7 @@ static void vcpu_migrate(struct vcpu *v)
|
||||
|
||||
/* Select new CPU. */
|
||||
old_cpu = v->processor;
|
||||
new_cpu = SCHED_OP(pick_cpu, v);
|
||||
new_cpu = SCHED_OP(VCPU2OP(v), pick_cpu, v);
|
||||
|
||||
/*
|
||||
* Transfer urgency status to new CPU before switching CPUs, as once
|
||||
@@ -369,19 +455,29 @@ void vcpu_force_reschedule(struct vcpu *v)
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used by cpu_hotplug code from stop_machine context.
|
||||
* Hence we can avoid needing to take certain locks.
|
||||
* This function is used by cpu_hotplug code from stop_machine context
|
||||
* and from cpupools to switch schedulers on a cpu.
|
||||
*/
|
||||
void cpu_disable_scheduler(void)
|
||||
int cpu_disable_scheduler(unsigned int cpu)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct cpupool *c;
|
||||
int ret = 0;
|
||||
|
||||
c = per_cpu(cpupool, cpu);
|
||||
if ( c == NULL )
|
||||
return ret;
|
||||
|
||||
for_each_domain ( d )
|
||||
{
|
||||
if ( d->cpupool != c )
|
||||
continue;
|
||||
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
vcpu_schedule_lock_irq(v);
|
||||
|
||||
if ( (cpus_weight(v->cpu_affinity) == 1) &&
|
||||
cpu_isset(cpu, v->cpu_affinity) )
|
||||
{
|
||||
@@ -395,26 +491,46 @@ void cpu_disable_scheduler(void)
|
||||
* be chosen when the timer is next re-set.
|
||||
*/
|
||||
if ( v->singleshot_timer.cpu == cpu )
|
||||
migrate_timer(&v->singleshot_timer, 0);
|
||||
{
|
||||
int cpu_mig = first_cpu(c->cpu_valid);
|
||||
if ( cpu_mig == cpu )
|
||||
cpu_mig = next_cpu(cpu_mig, c->cpu_valid);
|
||||
migrate_timer(&v->singleshot_timer, cpu_mig);
|
||||
}
|
||||
|
||||
if ( v->processor == cpu )
|
||||
{
|
||||
set_bit(_VPF_migrating, &v->pause_flags);
|
||||
vcpu_schedule_unlock_irq(v);
|
||||
vcpu_sleep_nosync(v);
|
||||
vcpu_migrate(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
vcpu_schedule_unlock_irq(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* A vcpu active in the hypervisor will not be migratable.
|
||||
* The caller should try again after releasing and reaquiring
|
||||
* all locks.
|
||||
*/
|
||||
if ( v->processor == cpu )
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity)
|
||||
{
|
||||
cpumask_t online_affinity, old_affinity;
|
||||
cpumask_t *online;
|
||||
|
||||
if ( v->domain->is_pinned )
|
||||
return -EINVAL;
|
||||
|
||||
cpus_and(online_affinity, *affinity, cpu_online_map);
|
||||
online = VCPU2ONLINE(v);
|
||||
cpus_and(online_affinity, *affinity, *online);
|
||||
if ( cpus_empty(online_affinity) )
|
||||
return -EINVAL;
|
||||
|
||||
@@ -723,7 +839,7 @@ long sched_adjust(struct domain *d, struct xen_domctl_scheduler_op *op)
|
||||
struct vcpu *v;
|
||||
long ret;
|
||||
|
||||
if ( (op->sched_id != ops.sched_id) ||
|
||||
if ( (op->sched_id != DOM2OP(d)->sched_id) ||
|
||||
((op->cmd != XEN_DOMCTL_SCHEDOP_putinfo) &&
|
||||
(op->cmd != XEN_DOMCTL_SCHEDOP_getinfo)) )
|
||||
return -EINVAL;
|
||||
@@ -750,7 +866,7 @@ long sched_adjust(struct domain *d, struct xen_domctl_scheduler_op *op)
|
||||
if ( d == current->domain )
|
||||
vcpu_schedule_lock_irq(current);
|
||||
|
||||
if ( (ret = SCHED_OP(adjust, d, op)) == 0 )
|
||||
if ( (ret = SCHED_OP(DOM2OP(d), adjust, d, op)) == 0 )
|
||||
TRACE_1D(TRC_SCHED_ADJDOM, d->domain_id);
|
||||
|
||||
if ( d == current->domain )
|
||||
@@ -797,6 +913,7 @@ static void schedule(void)
|
||||
{
|
||||
struct vcpu *prev = current, *next = NULL;
|
||||
s_time_t now = NOW();
|
||||
struct scheduler *sched = this_cpu(scheduler);
|
||||
struct schedule_data *sd;
|
||||
struct task_slice next_slice;
|
||||
|
||||
@@ -812,7 +929,7 @@ static void schedule(void)
|
||||
stop_timer(&sd->s_timer);
|
||||
|
||||
/* get policy-specific decision on scheduling... */
|
||||
next_slice = ops.do_schedule(now);
|
||||
next_slice = sched->do_schedule(sched, now);
|
||||
|
||||
next = next_slice.task;
|
||||
|
||||
@@ -871,6 +988,10 @@ static void schedule(void)
|
||||
update_vcpu_system_time(next);
|
||||
vcpu_periodic_timer_work(next);
|
||||
|
||||
TRACE_4D(TRC_SCHED_SWITCH,
|
||||
prev->domain->domain_id, prev->vcpu_id,
|
||||
next->domain->domain_id, next->vcpu_id);
|
||||
|
||||
context_switch(prev, next);
|
||||
}
|
||||
|
||||
@@ -884,7 +1005,7 @@ void context_saved(struct vcpu *prev)
|
||||
/* Check for migration request /after/ clearing running flag. */
|
||||
smp_mb();
|
||||
|
||||
SCHED_OP(context_saved, prev);
|
||||
SCHED_OP(VCPU2OP(prev), context_saved, prev);
|
||||
|
||||
if ( unlikely(test_bit(_VPF_migrating, &prev->pause_flags)) )
|
||||
vcpu_migrate(prev);
|
||||
@@ -920,6 +1041,19 @@ static void poll_timer_fn(void *data)
|
||||
vcpu_unblock(v);
|
||||
}
|
||||
|
||||
/* Get scheduler by id */
|
||||
const struct scheduler *scheduler_get_by_id(unsigned int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; schedulers[i] != NULL; i++ )
|
||||
{
|
||||
if ( schedulers[i]->sched_id == id )
|
||||
return schedulers[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialise the data structures. */
|
||||
void __init scheduler_init(void)
|
||||
{
|
||||
@@ -927,14 +1061,6 @@ void __init scheduler_init(void)
|
||||
|
||||
open_softirq(SCHEDULE_SOFTIRQ, schedule);
|
||||
|
||||
for_each_possible_cpu ( i )
|
||||
{
|
||||
spin_lock_init(&per_cpu(schedule_data, i)._lock);
|
||||
per_cpu(schedule_data, i).schedule_lock
|
||||
= &per_cpu(schedule_data, i)._lock;
|
||||
init_timer(&per_cpu(schedule_data, i).s_timer, s_timer_fn, NULL, i);
|
||||
}
|
||||
|
||||
for ( i = 0; schedulers[i] != NULL; i++ )
|
||||
{
|
||||
ops = *schedulers[i];
|
||||
@@ -948,43 +1074,125 @@ void __init scheduler_init(void)
|
||||
ops = *schedulers[0];
|
||||
}
|
||||
|
||||
for_each_possible_cpu ( i )
|
||||
{
|
||||
per_cpu(scheduler, i) = &ops;
|
||||
spin_lock_init(&per_cpu(schedule_data, i)._lock);
|
||||
per_cpu(schedule_data, i).schedule_lock
|
||||
= &per_cpu(schedule_data, i)._lock;
|
||||
init_timer(&per_cpu(schedule_data, i).s_timer, s_timer_fn, NULL, i);
|
||||
}
|
||||
|
||||
printk("Using scheduler: %s (%s)\n", ops.name, ops.opt_name);
|
||||
SCHED_OP(init);
|
||||
if ( SCHED_OP(&ops, init, 1) )
|
||||
panic("scheduler returned error on init\n");
|
||||
}
|
||||
|
||||
void dump_runq(unsigned char key)
|
||||
/* switch scheduler on cpu */
|
||||
void schedule_cpu_switch(unsigned int cpu, struct cpupool *c)
|
||||
{
|
||||
s_time_t now = NOW();
|
||||
int i;
|
||||
unsigned long flags;
|
||||
struct vcpu *v;
|
||||
void *vpriv = NULL;
|
||||
void *ppriv;
|
||||
void *ppriv_old;
|
||||
struct scheduler *old_ops;
|
||||
struct scheduler *new_ops;
|
||||
|
||||
local_irq_save(flags);
|
||||
old_ops = per_cpu(scheduler, cpu);
|
||||
new_ops = (c == NULL) ? &ops : &(c->sched);
|
||||
v = per_cpu(schedule_data, cpu).idle;
|
||||
ppriv = SCHED_OP(new_ops, alloc_pdata, cpu);
|
||||
if ( c != NULL )
|
||||
vpriv = SCHED_OP(new_ops, alloc_vdata, v, v->domain->sched_priv);
|
||||
|
||||
printk("Scheduler: %s (%s)\n", ops.name, ops.opt_name);
|
||||
SCHED_OP(dump_settings);
|
||||
printk("sched_smt_power_savings: %s\n",
|
||||
sched_smt_power_savings? "enabled":"disabled");
|
||||
printk("NOW=0x%08X%08X\n", (u32)(now>>32), (u32)now);
|
||||
spin_lock_irqsave(per_cpu(schedule_data, cpu).schedule_lock, flags);
|
||||
|
||||
for_each_online_cpu ( i )
|
||||
if ( c == NULL )
|
||||
{
|
||||
vpriv = v->sched_priv;
|
||||
v->sched_priv = per_cpu(schedule_data, cpu).sched_idlevpriv;
|
||||
}
|
||||
else
|
||||
{
|
||||
v->sched_priv = vpriv;
|
||||
vpriv = NULL;
|
||||
}
|
||||
SCHED_OP(old_ops, tick_suspend, cpu);
|
||||
per_cpu(scheduler, cpu) = new_ops;
|
||||
ppriv_old = per_cpu(schedule_data, cpu).sched_priv;
|
||||
per_cpu(schedule_data, cpu).sched_priv = ppriv;
|
||||
SCHED_OP(new_ops, tick_resume, cpu);
|
||||
SCHED_OP(new_ops, insert_vcpu, v);
|
||||
|
||||
spin_unlock_irqrestore(per_cpu(schedule_data, cpu).schedule_lock, flags);
|
||||
|
||||
if ( vpriv != NULL )
|
||||
SCHED_OP(old_ops, free_vdata, vpriv);
|
||||
SCHED_OP(old_ops, free_pdata, ppriv_old, cpu);
|
||||
}
|
||||
|
||||
/* init scheduler global data */
|
||||
int schedule_init_global(char *name, struct scheduler *sched)
|
||||
{
|
||||
int i;
|
||||
const struct scheduler *data;
|
||||
|
||||
data = &ops;
|
||||
for ( i = 0; (schedulers[i] != NULL) && (name != NULL) ; i++ )
|
||||
{
|
||||
if ( strcmp(schedulers[i]->opt_name, name) == 0 )
|
||||
{
|
||||
data = schedulers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy(sched, data, sizeof(*sched));
|
||||
return SCHED_OP(sched, init, 0);
|
||||
}
|
||||
|
||||
/* deinitialize scheduler global data */
|
||||
void schedule_deinit_global(struct scheduler *sched)
|
||||
{
|
||||
SCHED_OP(sched, deinit);
|
||||
}
|
||||
|
||||
void schedule_dump(struct cpupool *c)
|
||||
{
|
||||
int i;
|
||||
struct scheduler *sched;
|
||||
cpumask_t *cpus;
|
||||
|
||||
sched = (c == NULL) ? &ops : &(c->sched);
|
||||
cpus = (c == NULL) ? &cpupool_free_cpus : &c->cpu_valid;
|
||||
printk("Scheduler: %s (%s)\n", sched->name, sched->opt_name);
|
||||
SCHED_OP(sched, dump_settings);
|
||||
|
||||
for_each_cpu_mask (i, *cpus)
|
||||
{
|
||||
spin_lock(per_cpu(schedule_data, i).schedule_lock);
|
||||
printk("CPU[%02d] ", i);
|
||||
SCHED_OP(dump_cpu_state, i);
|
||||
SCHED_OP(sched, dump_cpu_state, i);
|
||||
spin_unlock(per_cpu(schedule_data, i).schedule_lock);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void sched_tick_suspend(void)
|
||||
{
|
||||
SCHED_OP(tick_suspend);
|
||||
struct scheduler *sched;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
sched = per_cpu(scheduler, cpu);
|
||||
SCHED_OP(sched, tick_suspend, cpu);
|
||||
}
|
||||
|
||||
void sched_tick_resume(void)
|
||||
{
|
||||
SCHED_OP(tick_resume);
|
||||
struct scheduler *sched;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
sched = per_cpu(scheduler, cpu);
|
||||
SCHED_OP(sched, tick_resume, cpu);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "xen.h"
|
||||
#include "grant_table.h"
|
||||
|
||||
#define XEN_DOMCTL_INTERFACE_VERSION 0x00000006
|
||||
#define XEN_DOMCTL_INTERFACE_VERSION 0x00000007
|
||||
|
||||
struct xenctl_cpumap {
|
||||
XEN_GUEST_HANDLE_64(uint8) bitmap;
|
||||
@@ -60,10 +60,10 @@ struct xen_domctl_createdomain {
|
||||
/* Should domain memory integrity be verifed by tboot during Sx? */
|
||||
#define _XEN_DOMCTL_CDF_s3_integrity 2
|
||||
#define XEN_DOMCTL_CDF_s3_integrity (1U<<_XEN_DOMCTL_CDF_s3_integrity)
|
||||
uint32_t flags;
|
||||
/* Disable out-of-sync shadow page tables? */
|
||||
#define _XEN_DOMCTL_CDF_oos_off 3
|
||||
#define XEN_DOMCTL_CDF_oos_off (1U<<_XEN_DOMCTL_CDF_oos_off)
|
||||
uint32_t flags;
|
||||
};
|
||||
typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t);
|
||||
@@ -106,6 +106,7 @@ struct xen_domctl_getdomaininfo {
|
||||
uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
|
||||
uint32_t ssidref;
|
||||
xen_domain_handle_t handle;
|
||||
uint32_t cpupool;
|
||||
};
|
||||
typedef struct xen_domctl_getdomaininfo xen_domctl_getdomaininfo_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_getdomaininfo_t);
|
||||
@@ -785,6 +786,30 @@ struct xen_domctl_mem_sharing_op {
|
||||
typedef struct xen_domctl_mem_sharing_op xen_domctl_mem_sharing_op_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_sharing_op_t);
|
||||
|
||||
/*
|
||||
* cpupool operations
|
||||
*/
|
||||
/* XEN_DOMCTL_cpupool_op */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_CREATE 1 /* C */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_DESTROY 2 /* D */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_INFO 3 /* I */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_ADDCPU 4 /* A */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_RMCPU 5 /* R */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_MOVEDOMAIN 6 /* M */
|
||||
#define XEN_DOMCTL_CPUPOOL_OP_FREEINFO 7 /* F */
|
||||
#define XEN_DOMCTL_CPUPOOL_PAR_ANY 0xFFFFFFFF
|
||||
struct xen_domctl_cpupool_op {
|
||||
uint32_t op; /* IN */
|
||||
uint32_t cpupool_id; /* IN: CDIARM OUT: CI */
|
||||
uint32_t sched_id; /* IN: C OUT: I */
|
||||
uint32_t domid; /* IN: M */
|
||||
uint32_t cpu; /* IN: AR */
|
||||
uint32_t n_dom; /* OUT: I */
|
||||
struct xenctl_cpumap cpumap; /* OUT: IF */
|
||||
};
|
||||
typedef struct xen_domctl_cpupool_op xen_domctl_cpupool_op_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpupool_op_t);
|
||||
|
||||
|
||||
struct xen_domctl {
|
||||
uint32_t cmd;
|
||||
@@ -846,6 +871,7 @@ struct xen_domctl {
|
||||
#define XEN_DOMCTL_gettscinfo 59
|
||||
#define XEN_DOMCTL_settscinfo 60
|
||||
#define XEN_DOMCTL_getpageframeinfo3 61
|
||||
#define XEN_DOMCTL_cpupool_op 62
|
||||
#define XEN_DOMCTL_gdbsx_guestmemio 1000
|
||||
#define XEN_DOMCTL_gdbsx_pausevcpu 1001
|
||||
#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
|
||||
@@ -894,6 +920,7 @@ struct xen_domctl {
|
||||
struct xen_domctl_debug_op debug_op;
|
||||
struct xen_domctl_mem_event_op mem_event_op;
|
||||
struct xen_domctl_mem_sharing_op mem_sharing_op;
|
||||
struct xen_domctl_cpupool_op cpupool_op;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
struct xen_domctl_cpuid cpuid;
|
||||
#endif
|
||||
|
||||
+45
-15
@@ -10,6 +10,12 @@
|
||||
|
||||
#include <xen/percpu.h>
|
||||
|
||||
/* A global pointer to the initial cpupool (POOL0). */
|
||||
extern struct cpupool *cpupool0;
|
||||
|
||||
/* cpus currently in no cpupool */
|
||||
extern cpumask_t cpupool_free_cpus;
|
||||
|
||||
/*
|
||||
* In order to allow a scheduler to remap the lock->cpu mapping,
|
||||
* we have a per-cpu pointer, along with a pre-allocated set of
|
||||
@@ -26,11 +32,14 @@ struct schedule_data {
|
||||
struct vcpu *curr; /* current task */
|
||||
struct vcpu *idle; /* idle task for this cpu */
|
||||
void *sched_priv;
|
||||
void *sched_idlevpriv; /* default scheduler vcpu data */
|
||||
struct timer s_timer; /* scheduling timer */
|
||||
atomic_t urgent_count; /* how many urgent vcpus */
|
||||
} __cacheline_aligned;
|
||||
|
||||
DECLARE_PER_CPU(struct schedule_data, schedule_data);
|
||||
DECLARE_PER_CPU(struct scheduler *, scheduler);
|
||||
DECLARE_PER_CPU(struct cpupool *, cpupool);
|
||||
|
||||
static inline void vcpu_schedule_lock(struct vcpu *v)
|
||||
{
|
||||
@@ -78,29 +87,50 @@ struct scheduler {
|
||||
char *name; /* full name for this scheduler */
|
||||
char *opt_name; /* option name for this scheduler */
|
||||
unsigned int sched_id; /* ID for this scheduler */
|
||||
void *sched_data; /* global data pointer */
|
||||
|
||||
void (*init) (void);
|
||||
int (*init) (struct scheduler *, int);
|
||||
void (*deinit) (struct scheduler *);
|
||||
|
||||
int (*init_domain) (struct domain *);
|
||||
void (*destroy_domain) (struct domain *);
|
||||
void (*free_vdata) (struct scheduler *, void *);
|
||||
void * (*alloc_vdata) (struct scheduler *, struct vcpu *,
|
||||
void *);
|
||||
void (*free_pdata) (struct scheduler *, void *, int);
|
||||
void * (*alloc_pdata) (struct scheduler *, int);
|
||||
void (*free_domdata) (struct scheduler *, void *);
|
||||
void * (*alloc_domdata) (struct scheduler *, struct domain *);
|
||||
|
||||
int (*init_vcpu) (struct vcpu *);
|
||||
void (*destroy_vcpu) (struct vcpu *);
|
||||
int (*init_domain) (struct scheduler *, struct domain *);
|
||||
void (*destroy_domain) (struct scheduler *, struct domain *);
|
||||
|
||||
void (*sleep) (struct vcpu *);
|
||||
void (*wake) (struct vcpu *);
|
||||
void (*context_saved) (struct vcpu *);
|
||||
void (*insert_vcpu) (struct scheduler *, struct vcpu *);
|
||||
void (*destroy_vcpu) (struct scheduler *, struct vcpu *);
|
||||
|
||||
struct task_slice (*do_schedule) (s_time_t);
|
||||
void (*sleep) (struct scheduler *, struct vcpu *);
|
||||
void (*wake) (struct scheduler *, struct vcpu *);
|
||||
void (*context_saved) (struct scheduler *, struct vcpu *);
|
||||
|
||||
int (*pick_cpu) (struct vcpu *);
|
||||
int (*adjust) (struct domain *,
|
||||
struct task_slice (*do_schedule) (struct scheduler *, s_time_t);
|
||||
|
||||
int (*pick_cpu) (struct scheduler *, struct vcpu *);
|
||||
int (*adjust) (struct scheduler *, struct domain *,
|
||||
struct xen_domctl_scheduler_op *);
|
||||
void (*dump_settings) (void);
|
||||
void (*dump_cpu_state) (int);
|
||||
void (*dump_settings) (struct scheduler *);
|
||||
void (*dump_cpu_state) (struct scheduler *, int);
|
||||
|
||||
void (*tick_suspend) (void);
|
||||
void (*tick_resume) (void);
|
||||
void (*tick_suspend) (struct scheduler *, unsigned int);
|
||||
void (*tick_resume) (struct scheduler *, unsigned int);
|
||||
};
|
||||
|
||||
struct cpupool
|
||||
{
|
||||
int cpupool_id;
|
||||
cpumask_t cpu_valid; /* all cpus assigned to pool */
|
||||
struct cpupool *next;
|
||||
unsigned int n_dom;
|
||||
struct scheduler sched;
|
||||
};
|
||||
|
||||
const struct scheduler *scheduler_get_by_id(unsigned int id);
|
||||
|
||||
#endif /* __XEN_SCHED_IF_H__ */
|
||||
+21
-1
@@ -213,6 +213,7 @@ struct domain
|
||||
|
||||
/* Scheduling. */
|
||||
void *sched_priv; /* scheduler-specific data */
|
||||
struct cpupool *cpupool;
|
||||
|
||||
struct domain *next_in_list;
|
||||
struct domain *next_in_hashbucket;
|
||||
@@ -465,6 +466,7 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor);
|
||||
void sched_destroy_vcpu(struct vcpu *v);
|
||||
int sched_init_domain(struct domain *d);
|
||||
void sched_destroy_domain(struct domain *d);
|
||||
int sched_move_domain(struct domain *d, struct cpupool *c);
|
||||
long sched_adjust(struct domain *, struct xen_domctl_scheduler_op *);
|
||||
int sched_id(void);
|
||||
void sched_tick_suspend(void);
|
||||
@@ -575,8 +577,13 @@ void domain_pause_by_systemcontroller(struct domain *d);
|
||||
void domain_unpause_by_systemcontroller(struct domain *d);
|
||||
void cpu_init(void);
|
||||
|
||||
struct scheduler;
|
||||
|
||||
int schedule_init_global(char *name, struct scheduler *sched);
|
||||
void schedule_deinit_global(struct scheduler *sched);
|
||||
void schedule_cpu_switch(unsigned int cpu, struct cpupool *c);
|
||||
void vcpu_force_reschedule(struct vcpu *v);
|
||||
void cpu_disable_scheduler(void);
|
||||
int cpu_disable_scheduler(unsigned int cpu);
|
||||
int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity);
|
||||
|
||||
void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate);
|
||||
@@ -607,6 +614,19 @@ extern enum cpufreq_controller {
|
||||
FREQCTL_none, FREQCTL_dom0_kernel, FREQCTL_xen
|
||||
} cpufreq_controller;
|
||||
|
||||
#define CPUPOOLID_NONE -1
|
||||
|
||||
struct cpupool *cpupool_create(int poolid, char *sched);
|
||||
int cpupool_destroy(struct cpupool *c);
|
||||
int cpupool0_cpu_assign(struct cpupool *c);
|
||||
int cpupool_assign_ncpu(struct cpupool *c, int ncpu);
|
||||
void cpupool_cpu_add(unsigned int cpu);
|
||||
int cpupool_cpu_remove(unsigned int cpu);
|
||||
int cpupool_add_domain(struct domain *d, int poolid);
|
||||
void cpupool_rm_domain(struct domain *d);
|
||||
int cpupool_do_domctl(struct xen_domctl_cpupool_op *op);
|
||||
#define num_cpupool_cpus(c) (cpus_weight((c)->cpu_valid))
|
||||
|
||||
#endif /* __SCHED_H__ */
|
||||
|
||||
/*
|
||||
|
||||