xen/sched: split scheduler vtable from struct scheduler

struct scheduler currently serves two purposes: it is the static
vtable a scheduler backend defines (name, opt_name, sched_id, and
all its function pointers), and it is also the per-cpupool runtime
object scheduler_alloc() allocates. Being the same type forces
scheduler_alloc() to memcpy() the whole vtable into a fresh
allocation per cpupool, duplicating identical function pointers
across every cpupool using the same scheduler.

Split the vtable out into its own type, struct sched_ops, so it
can be shared by every cpupool using a given scheduler instead of
copied per cpupool. struct scheduler is left holding only what is
actually per-instance: a pointer to the shared sched_ops, plus
sched_data and cpupool. scheduler_alloc() now stores a pointer to
the matching sched_ops instance instead of copying its fields and
uses xzalloc() to zero-initialize the struct. Every accessor in
private.h is updated from s->field to s->ops->field to match.

Every in-tree scheduler backend (credit, credit2, rtds, arinc653,
null) is converted from struct scheduler to struct sched_ops.
Also drop the generic comment in arinc653.c.

A handful of call sites elsewhere read a scheduler's name,
opt_name or sched_id directly and are updated to go through
->ops as well.

Signed-off-by: Furkan Caliskan <frn1furkan10@gmail.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Acked-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
This commit is contained in:
Furkan Caliskan authored and Jan Beulich committed 2026-08-12 10:48:21 +02:00
1 parent 015aa2e11f
commit 58db743e3b
8 files changed
+90 -87

No files matched your search

+1 -8
View File
@@ -702,17 +702,10 @@ a653sched_adjust_global(const struct scheduler *ops,
} }
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
/** static const struct sched_ops sched_arinc653_def = {
* This structure defines our scheduler for Xen.
* The entries tell Xen where to find our scheduler-specific
* callback functions.
* The symbol must be visible to the rest of Xen at link time.
*/
static const struct scheduler sched_arinc653_def = {
.name = "ARINC 653 Scheduler", .name = "ARINC 653 Scheduler",
.opt_name = "arinc653", .opt_name = "arinc653",
.sched_id = XEN_SCHEDULER_ARINC653, .sched_id = XEN_SCHEDULER_ARINC653,
.sched_data = NULL,
.init = a653sched_init, .init = a653sched_init,
.deinit = a653sched_deinit, .deinit = a653sched_deinit,
+30 -21
View File
@@ -87,7 +87,8 @@ DEFINE_PER_CPU(cpumask_t, cpumask_scratch);
/* How many urgent vcpus. */ /* How many urgent vcpus. */
DEFINE_PER_CPU(atomic_t, sched_urgent_count); DEFINE_PER_CPU(atomic_t, sched_urgent_count);
extern const struct scheduler *__start_schedulers_array[], *__end_schedulers_array[]; extern const struct sched_ops *__start_schedulers_array[];
extern const struct sched_ops *__end_schedulers_array[];
#define NUM_SCHEDULERS (__end_schedulers_array - __start_schedulers_array) #define NUM_SCHEDULERS (__end_schedulers_array - __start_schedulers_array)
#define schedulers __start_schedulers_array #define schedulers __start_schedulers_array
@@ -127,10 +128,9 @@ static void cf_check sched_idle_schedule(
unit->next_task = sched_idle_unit(cpu); unit->next_task = sched_idle_unit(cpu);
} }
static struct scheduler sched_idle_ops = { static struct sched_ops sched_idle_sched_ops = {
.name = "Idle Scheduler", .name = "Idle Scheduler",
.opt_name = "idle", .opt_name = "idle",
.sched_data = NULL,
.pick_resource = sched_idle_res_pick, .pick_resource = sched_idle_res_pick,
.do_schedule = sched_idle_schedule, .do_schedule = sched_idle_schedule,
@@ -139,6 +139,11 @@ static struct scheduler sched_idle_ops = {
.free_udata = sched_idle_free_udata, .free_udata = sched_idle_free_udata,
}; };
static struct scheduler sched_idle_ops = {
.ops = &sched_idle_sched_ops,
.sched_data = NULL,
};
static inline struct vcpu *unit2vcpu_cpu(const struct sched_unit *unit, static inline struct vcpu *unit2vcpu_cpu(const struct sched_unit *unit,
unsigned int cpu) unsigned int cpu)
{ {
@@ -2081,7 +2086,7 @@ long do_set_timer_op(s_time_t timeout)
/* scheduler_id - fetch ID of current scheduler */ /* scheduler_id - fetch ID of current scheduler */
int scheduler_id(void) int scheduler_id(void)
{ {
return operations.sched_id; return operations.ops->sched_id;
} }
#endif #endif
@@ -2090,7 +2095,7 @@ long sched_adjust(struct domain *d, struct xen_domctl_scheduler_op *op)
{ {
long ret; long ret;
if ( op->sched_id != dom_scheduler(d)->sched_id ) if ( op->sched_id != dom_scheduler(d)->ops->sched_id )
return -EINVAL; return -EINVAL;
switch ( op->cmd ) switch ( op->cmd )
@@ -2132,7 +2137,7 @@ long sched_adjust_global(struct xen_sysctl_scheduler_op *op)
rcu_read_lock(&sched_res_rculock); rcu_read_lock(&sched_res_rculock);
rc = ((op->sched_id == pool->sched->sched_id) rc = ((op->sched_id == pool->sched->ops->sched_id)
? sched_adjust_cpupool(pool->sched, op) : -EINVAL); ? sched_adjust_cpupool(pool->sched, op) : -EINVAL);
rcu_read_unlock(&sched_res_rculock); rcu_read_unlock(&sched_res_rculock);
@@ -2299,7 +2304,7 @@ static struct sched_unit *do_schedule(struct sched_unit *prev, s_time_t now,
struct sched_unit *next; struct sched_unit *next;
/* get policy-specific decision on scheduling... */ /* get policy-specific decision on scheduling... */
sched->do_schedule(sched, prev, now, sched_tasklet_check(cpu)); sched->ops->do_schedule(sched, prev, now, sched_tasklet_check(cpu));
next = prev->next_task; next = prev->next_task;
@@ -2989,7 +2994,7 @@ void scheduler_enable(void)
} }
static inline static inline
const struct scheduler *__init sched_get_by_name(const char *sched_name) const struct sched_ops *__init sched_ops_get_by_name(const char *sched_name)
{ {
unsigned int i; unsigned int i;
@@ -3002,16 +3007,16 @@ const struct scheduler *__init sched_get_by_name(const char *sched_name)
int __init sched_get_id_by_name(const char *sched_name) int __init sched_get_id_by_name(const char *sched_name)
{ {
const struct scheduler *scheduler = sched_get_by_name(sched_name); const struct sched_ops *ops = sched_ops_get_by_name(sched_name);
return scheduler ? scheduler->sched_id : -1; return ops ? ops->sched_id : -1;
} }
/* Initialise the data structures. */ /* Initialise the data structures. */
void __init scheduler_init(void) void __init scheduler_init(void)
{ {
struct domain *idle_domain; struct domain *idle_domain;
const struct scheduler *scheduler; const struct sched_ops *ops;
int i; int i;
scheduler_enable(); scheduler_enable();
@@ -3044,21 +3049,23 @@ void __init scheduler_init(void)
} }
} }
scheduler = sched_get_by_name(opt_sched); ops = sched_ops_get_by_name(opt_sched);
if ( !scheduler ) if ( !ops )
{ {
printk("Could not find scheduler: %s\n", opt_sched); printk("Could not find scheduler: %s\n", opt_sched);
scheduler = sched_get_by_name(CONFIG_SCHED_DEFAULT); ops = sched_ops_get_by_name(CONFIG_SCHED_DEFAULT);
BUG_ON(!scheduler); BUG_ON(!ops);
printk("Using '%s' (%s)\n", scheduler->name, scheduler->opt_name); printk("Using '%s' (%s)\n", ops->name, ops->opt_name);
} }
operations = *scheduler;
operations.ops = ops;
if ( cpu_schedule_up(0) ) if ( cpu_schedule_up(0) )
BUG(); BUG();
register_cpu_notifier(&cpu_schedule_nfb); register_cpu_notifier(&cpu_schedule_nfb);
printk("Using scheduler: %s (%s)\n", operations.name, operations.opt_name); printk("Using scheduler: %s (%s)\n",
operations.ops->name, operations.ops->opt_name);
if ( sched_init(&operations) ) if ( sched_init(&operations) )
panic("scheduler returned error on init\n"); panic("scheduler returned error on init\n");
@@ -3411,12 +3418,14 @@ struct scheduler *scheduler_alloc(unsigned int sched_id)
for ( i = 0; i < NUM_SCHEDULERS; i++ ) for ( i = 0; i < NUM_SCHEDULERS; i++ )
if ( schedulers[i] && schedulers[i]->sched_id == sched_id ) if ( schedulers[i] && schedulers[i]->sched_id == sched_id )
goto found; goto found;
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
found: found:
if ( (sched = xmalloc(struct scheduler)) == NULL ) if ( (sched = xzalloc(struct scheduler)) == NULL )
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memcpy(sched, schedulers[i], sizeof(*sched)); sched->ops = schedulers[i];
if ( (ret = sched_init(sched)) != 0 ) if ( (ret = sched_init(sched)) != 0 )
{ {
xfree(sched); xfree(sched);
@@ -3447,7 +3456,7 @@ void schedule_dump(struct cpupool *c)
{ {
sched = c->sched; sched = c->sched;
cpus = c->res_valid; cpus = c->res_valid;
printk("Scheduler: %s (%s)\n", sched->name, sched->opt_name); printk("Scheduler: %s (%s)\n", sched->ops->name, sched->ops->opt_name);
sched_dump_settings(sched); sched_dump_settings(sched);
} }
else else
+4 -3
View File
@@ -338,7 +338,8 @@ static struct cpupool *cpupool_create(unsigned int poolid,
spin_unlock(&cpupool_lock); spin_unlock(&cpupool_lock);
debugtrace_printk("Created cpupool %u with scheduler %s (%s)\n", debugtrace_printk("Created cpupool %u with scheduler %s (%s)\n",
c->cpupool_id, c->sched->name, c->sched->opt_name); c->cpupool_id, c->sched->ops->name,
c->sched->ops->opt_name);
return c; return c;
@@ -862,7 +863,7 @@ int cpupool_do_sysctl(struct xen_sysctl_cpupool_op *op)
if ( c == NULL ) if ( c == NULL )
break; break;
op->cpupool_id = c->cpupool_id; op->cpupool_id = c->cpupool_id;
op->sched_id = c->sched->sched_id; op->sched_id = c->sched->ops->sched_id;
op->n_dom = c->n_dom; op->n_dom = c->n_dom;
ret = cpumask_to_xenctl_bitmap(&op->cpumap, c->cpu_valid); ret = cpumask_to_xenctl_bitmap(&op->cpumap, c->cpu_valid);
cpupool_put(c); cpupool_put(c);
@@ -1294,7 +1295,7 @@ struct cpupool *__init cpupool_create_pool(unsigned int pool_id, int sched_id)
struct cpupool *pool; struct cpupool *pool;
if ( sched_id < 0 ) if ( sched_id < 0 )
sched_id = scheduler_get_default()->sched_id; sched_id = scheduler_get_default()->ops->sched_id;
pool = cpupool_create(pool_id, sched_id); pool = cpupool_create(pool_id, sched_id);
+1 -2
View File
@@ -2277,11 +2277,10 @@ csched_deinit(struct scheduler *ops)
} }
} }
static const struct scheduler sched_credit_def = { static const struct sched_ops sched_credit_def = {
.name = "SMP Credit Scheduler", .name = "SMP Credit Scheduler",
.opt_name = "credit", .opt_name = "credit",
.sched_id = XEN_SCHEDULER_CREDIT, .sched_id = XEN_SCHEDULER_CREDIT,
.sched_data = NULL,
.global_init = csched_global_init, .global_init = csched_global_init,
+1 -2
View File
@@ -4230,11 +4230,10 @@ csched2_deinit(struct scheduler *ops)
xfree(prv); xfree(prv);
} }
static const struct scheduler sched_credit2_def = { static const struct sched_ops sched_credit2_def = {
.name = "SMP Credit Scheduler rev2", .name = "SMP Credit Scheduler rev2",
.opt_name = "credit2", .opt_name = "credit2",
.sched_id = XEN_SCHEDULER_CREDIT2, .sched_id = XEN_SCHEDULER_CREDIT2,
.sched_data = NULL,
.global_init = csched2_global_init, .global_init = csched2_global_init,
+1 -2
View File
@@ -1037,11 +1037,10 @@ static void cf_check null_dump(const struct scheduler *ops)
spin_unlock_irqrestore(&prv->lock, flags); spin_unlock_irqrestore(&prv->lock, flags);
} }
static const struct scheduler sched_null_def = { static const struct sched_ops sched_null_def = {
.name = "null Scheduler", .name = "null Scheduler",
.opt_name = "null", .opt_name = "null",
.sched_id = XEN_SCHEDULER_NULL, .sched_id = XEN_SCHEDULER_NULL,
.sched_data = NULL,
.init = null_init, .init = null_init,
.deinit = null_deinit, .deinit = null_deinit,
+51 -47
View File
@@ -294,12 +294,10 @@ static inline spinlock_t *pcpu_schedule_trylock(unsigned int cpu)
return NULL; return NULL;
} }
struct scheduler { struct sched_ops {
const char *name; /* full name for this scheduler */ const char *name; /* full name for this sched_ops */
const char *opt_name; /* option name for this scheduler */ const char *opt_name; /* option name for this sched_ops */
unsigned int sched_id; /* ID for this scheduler */ unsigned int sched_id; /* ID for this sched_ops */
void *sched_data; /* global data pointer */
struct cpupool *cpupool;/* points to this scheduler's pool */
int (*global_init) (void); int (*global_init) (void);
@@ -366,127 +364,133 @@ struct scheduler {
struct sched_resource *sr); struct sched_resource *sr);
}; };
struct scheduler {
const struct sched_ops *ops; /* shared, read-only dispatch table */
void *sched_data; /* per-cpupool scheduler-private data */
struct cpupool *cpupool; /* points to this scheduler's pool */
};
static inline int sched_init(struct scheduler *s) static inline int sched_init(struct scheduler *s)
{ {
return s->init(s); return s->ops->init(s);
} }
static inline void sched_deinit(struct scheduler *s) static inline void sched_deinit(struct scheduler *s)
{ {
s->deinit(s); s->ops->deinit(s);
} }
static inline spinlock_t *sched_switch_sched(struct scheduler *s, static inline spinlock_t *sched_switch_sched(struct scheduler *s,
unsigned int cpu, unsigned int cpu,
void *pdata, void *vdata) void *pdata, void *vdata)
{ {
return s->switch_sched(s, cpu, pdata, vdata); return s->ops->switch_sched(s, cpu, pdata, vdata);
} }
static inline void sched_dump_settings(const struct scheduler *s) static inline void sched_dump_settings(const struct scheduler *s)
{ {
if ( s->dump_settings ) if ( s->ops->dump_settings )
s->dump_settings(s); s->ops->dump_settings(s);
} }
static inline void sched_dump_cpu_state(const struct scheduler *s, int cpu) static inline void sched_dump_cpu_state(const struct scheduler *s, int cpu)
{ {
if ( s->dump_cpu_state ) if ( s->ops->dump_cpu_state )
s->dump_cpu_state(s, cpu); s->ops->dump_cpu_state(s, cpu);
} }
static inline void *sched_alloc_domdata(const struct scheduler *s, static inline void *sched_alloc_domdata(const struct scheduler *s,
struct domain *d) struct domain *d)
{ {
return s->alloc_domdata ? s->alloc_domdata(s, d) : NULL; return s->ops->alloc_domdata ? s->ops->alloc_domdata(s, d) : NULL;
} }
static inline void sched_free_domdata(const struct scheduler *s, static inline void sched_free_domdata(const struct scheduler *s,
void *data) void *data)
{ {
ASSERT(s->free_domdata || !data); ASSERT(s->ops->free_domdata || !data);
if ( s->free_domdata ) if ( s->ops->free_domdata )
s->free_domdata(s, data); s->ops->free_domdata(s, data);
} }
static inline void *sched_alloc_pdata(const struct scheduler *s, int cpu) static inline void *sched_alloc_pdata(const struct scheduler *s, int cpu)
{ {
return s->alloc_pdata ? s->alloc_pdata(s, cpu) : NULL; return s->ops->alloc_pdata ? s->ops->alloc_pdata(s, cpu) : NULL;
} }
static inline void sched_free_pdata(const struct scheduler *s, void *data, static inline void sched_free_pdata(const struct scheduler *s, void *data,
int cpu) int cpu)
{ {
ASSERT(s->free_pdata || !data); ASSERT(s->ops->free_pdata || !data);
if ( s->free_pdata ) if ( s->ops->free_pdata )
s->free_pdata(s, data, cpu); s->ops->free_pdata(s, data, cpu);
} }
static inline void sched_deinit_pdata(const struct scheduler *s, void *data, static inline void sched_deinit_pdata(const struct scheduler *s, void *data,
int cpu) int cpu)
{ {
if ( s->deinit_pdata ) if ( s->ops->deinit_pdata )
s->deinit_pdata(s, data, cpu); s->ops->deinit_pdata(s, data, cpu);
} }
static inline void *sched_alloc_udata(const struct scheduler *s, static inline void *sched_alloc_udata(const struct scheduler *s,
struct sched_unit *unit, void *dom_data) struct sched_unit *unit, void *dom_data)
{ {
return s->alloc_udata(s, unit, dom_data); return s->ops->alloc_udata(s, unit, dom_data);
} }
static inline void sched_free_udata(const struct scheduler *s, void *data) static inline void sched_free_udata(const struct scheduler *s, void *data)
{ {
s->free_udata(s, data); s->ops->free_udata(s, data);
} }
static inline void sched_insert_unit(const struct scheduler *s, static inline void sched_insert_unit(const struct scheduler *s,
struct sched_unit *unit) struct sched_unit *unit)
{ {
if ( s->insert_unit ) if ( s->ops->insert_unit )
s->insert_unit(s, unit); s->ops->insert_unit(s, unit);
} }
static inline void sched_remove_unit(const struct scheduler *s, static inline void sched_remove_unit(const struct scheduler *s,
struct sched_unit *unit) struct sched_unit *unit)
{ {
if ( s->remove_unit ) if ( s->ops->remove_unit )
s->remove_unit(s, unit); s->ops->remove_unit(s, unit);
} }
static inline void sched_sleep(const struct scheduler *s, static inline void sched_sleep(const struct scheduler *s,
struct sched_unit *unit) struct sched_unit *unit)
{ {
if ( s->sleep ) if ( s->ops->sleep )
s->sleep(s, unit); s->ops->sleep(s, unit);
} }
static inline void sched_wake(const struct scheduler *s, static inline void sched_wake(const struct scheduler *s,
struct sched_unit *unit) struct sched_unit *unit)
{ {
if ( s->wake ) if ( s->ops->wake )
s->wake(s, unit); s->ops->wake(s, unit);
} }
static inline void sched_yield(const struct scheduler *s, static inline void sched_yield(const struct scheduler *s,
struct sched_unit *unit) struct sched_unit *unit)
{ {
if ( s->yield ) if ( s->ops->yield )
s->yield(s, unit); s->ops->yield(s, unit);
} }
static inline void sched_context_saved(const struct scheduler *s, static inline void sched_context_saved(const struct scheduler *s,
struct sched_unit *unit) struct sched_unit *unit)
{ {
if ( s->context_saved ) if ( s->ops->context_saved )
s->context_saved(s, unit); s->ops->context_saved(s, unit);
} }
static inline void sched_migrate(const struct scheduler *s, static inline void sched_migrate(const struct scheduler *s,
struct sched_unit *unit, unsigned int cpu) struct sched_unit *unit, unsigned int cpu)
{ {
if ( s->migrate ) if ( s->ops->migrate )
s->migrate(s, unit, cpu); s->ops->migrate(s, unit, cpu);
else else
sched_set_res(unit, get_sched_res(cpu)); sched_set_res(unit, get_sched_res(cpu));
} }
@@ -494,7 +498,7 @@ static inline void sched_migrate(const struct scheduler *s,
static inline struct sched_resource *sched_pick_resource( static inline struct sched_resource *sched_pick_resource(
const struct scheduler *s, const struct sched_unit *unit) const struct scheduler *s, const struct sched_unit *unit)
{ {
return s->pick_resource(s, unit); return s->ops->pick_resource(s, unit);
} }
static inline void sched_adjust_affinity(const struct scheduler *s, static inline void sched_adjust_affinity(const struct scheduler *s,
@@ -502,29 +506,29 @@ static inline void sched_adjust_affinity(const struct scheduler *s,
const cpumask_t *hard, const cpumask_t *hard,
const cpumask_t *soft) const cpumask_t *soft)
{ {
if ( s->adjust_affinity ) if ( s->ops->adjust_affinity )
s->adjust_affinity(s, unit, hard, soft); s->ops->adjust_affinity(s, unit, hard, soft);
} }
static inline int sched_adjust_dom(const struct scheduler *s, struct domain *d, static inline int sched_adjust_dom(const struct scheduler *s, struct domain *d,
struct xen_domctl_scheduler_op *op) struct xen_domctl_scheduler_op *op)
{ {
return s->adjust ? s->adjust(s, d, op) : 0; return s->ops->adjust ? s->ops->adjust(s, d, op) : 0;
} }
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static inline int sched_adjust_cpupool(const struct scheduler *s, static inline int sched_adjust_cpupool(const struct scheduler *s,
struct xen_sysctl_scheduler_op *op) struct xen_sysctl_scheduler_op *op)
{ {
return s->adjust_global ? s->adjust_global(s, op) : 0; return s->ops->adjust_global ? s->ops->adjust_global(s, op) : 0;
} }
#endif #endif
static inline void sched_move_timers(const struct scheduler *s, static inline void sched_move_timers(const struct scheduler *s,
struct sched_resource *sr) struct sched_resource *sr)
{ {
if ( s->move_timers ) if ( s->ops->move_timers )
s->move_timers(s, sr); s->ops->move_timers(s, sr);
} }
static inline void sched_unit_pause_nosync(const struct sched_unit *unit) static inline void sched_unit_pause_nosync(const struct sched_unit *unit)
@@ -543,7 +547,7 @@ static inline void sched_unit_unpause(const struct sched_unit *unit)
vcpu_unpause(v); vcpu_unpause(v);
} }
#define REGISTER_SCHEDULER(x) static const struct scheduler *x##_entry \ #define REGISTER_SCHEDULER(x) static const struct sched_ops *x##_entry \
__used_section(".data.schedulers") = &(x) __used_section(".data.schedulers") = &(x)
struct cpupool struct cpupool
+1 -2
View File
@@ -1617,11 +1617,10 @@ static void cf_check repl_timer_handler(void *data)
spin_unlock_irq(&prv->lock); spin_unlock_irq(&prv->lock);
} }
static const struct scheduler sched_rtds_def = { static const struct sched_ops sched_rtds_def = {
.name = "SMP RTDS Scheduler", .name = "SMP RTDS Scheduler",
.opt_name = "rtds", .opt_name = "rtds",
.sched_id = XEN_SCHEDULER_RTDS, .sched_id = XEN_SCHEDULER_RTDS,
.sched_data = NULL,
.dump_cpu_state = rt_dump_pcpu, .dump_cpu_state = rt_dump_pcpu,
.dump_settings = rt_dump, .dump_settings = rt_dump,
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.