Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,10 @@
config RV_MON_DEADLINE
depends on RV
bool "deadline monitor"
help
Collection of monitors to check the deadline scheduler and server
behave according to specifications. Enable this to enable all
scheduler specification supported by the current kernel.
For further information, see:
Documentation/trace/rv/monitor_deadline.rst
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rv.h>
#include <linux/kallsyms.h>
#define MODULE_NAME "deadline"
#include "deadline.h"
struct rv_monitor rv_deadline = {
.name = "deadline",
.description = "container for several deadline scheduler specifications.",
.enable = NULL,
.disable = NULL,
.reset = NULL,
.enabled = 0,
};
/* Used by other monitors */
struct sched_class *rv_ext_sched_class;
static int __init register_deadline(void)
{
if (IS_ENABLED(CONFIG_SCHED_CLASS_EXT)) {
rv_ext_sched_class = (void *)kallsyms_lookup_name("ext_sched_class");
if (!rv_ext_sched_class)
pr_warn("rv: Missing ext_sched_class, monitors may not work.\n");
}
return rv_register_monitor(&rv_deadline, NULL);
}
static void __exit unregister_deadline(void)
{
rv_unregister_monitor(&rv_deadline);
}
module_init(register_deadline);
module_exit(unregister_deadline);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
MODULE_DESCRIPTION("deadline: container for several deadline scheduler specifications.");
@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/sched/deadline.h>
#include <asm/syscall.h>
#include <uapi/linux/sched/types.h>
#include <trace/events/sched.h>
/*
* Dummy values if not available
*/
#ifndef __NR_sched_setscheduler
#define __NR_sched_setscheduler -__COUNTER__
#endif
#ifndef __NR_sched_setattr
#define __NR_sched_setattr -__COUNTER__
#endif
extern struct rv_monitor rv_deadline;
/* Initialised when registering the deadline container */
extern struct sched_class *rv_ext_sched_class;
/*
* If both have dummy values, the syscalls are not supported and we don't even
* need to register the handler.
*/
static inline bool should_skip_syscall_handle(void)
{
return __NR_sched_setattr < 0 && __NR_sched_setscheduler < 0;
}
/*
* is_supported_type - return true if @type is supported by the deadline monitors
*/
static inline bool is_supported_type(u8 type)
{
return type == DL_TASK || type == DL_SERVER_FAIR || type == DL_SERVER_EXT;
}
/*
* is_server_type - return true if @type is a supported server
*/
static inline bool is_server_type(u8 type)
{
return is_supported_type(type) && type != DL_TASK;
}
/*
* Use negative numbers for the server.
* Currently only one fair server per CPU, may change in the future.
*/
#define fair_server_id(cpu) (-cpu)
#define ext_server_id(cpu) (-cpu - num_possible_cpus())
#define NO_SERVER_ID (-2 * num_possible_cpus())
/*
* Get a unique id used for dl entities
*
* The cpu is not required for tasks as the pid is used there, if this function
* is called on a dl_se that for sure corresponds to a task, DL_TASK can be
* used in place of cpu.
* We need the cpu for servers as it is provided in the tracepoint and we
* cannot easily retrieve it from the dl_se (requires the struct rq definition).
*/
static inline int get_entity_id(struct sched_dl_entity *dl_se, int cpu, u8 type)
{
if (dl_server(dl_se) && type != DL_TASK) {
if (type == DL_SERVER_FAIR)
return fair_server_id(cpu);
if (type == DL_SERVER_EXT)
return ext_server_id(cpu);
return NO_SERVER_ID;
}
return dl_task_of(dl_se)->pid;
}
static inline bool task_is_scx_enabled(struct task_struct *tsk)
{
return IS_ENABLED(CONFIG_SCHED_CLASS_EXT) &&
tsk->sched_class == rv_ext_sched_class;
}
/* Expand id and target as arguments for da functions */
#define EXPAND_ID(dl_se, cpu, type) get_entity_id(dl_se, cpu, type), dl_se
#define EXPAND_ID_TASK(tsk) get_entity_id(&tsk->dl, task_cpu(tsk), DL_TASK), &tsk->dl
static inline u8 get_server_type(struct task_struct *tsk)
{
if (tsk->policy == SCHED_NORMAL || tsk->policy == SCHED_EXT ||
tsk->policy == SCHED_BATCH || tsk->policy == SCHED_IDLE)
return task_is_scx_enabled(tsk) ? DL_SERVER_EXT : DL_SERVER_FAIR;
return DL_OTHER;
}
static inline int extract_params(struct pt_regs *regs, long id, pid_t *pid_out)
{
size_t size = offsetofend(struct sched_attr, sched_flags);
struct sched_attr __user *uattr;
struct sched_attr attr;
int new_policy = -1, ret;
unsigned long args[6];
switch (id) {
case __NR_sched_setscheduler:
syscall_get_arguments(current, regs, args);
*pid_out = args[0];
new_policy = args[1];
break;
case __NR_sched_setattr:
syscall_get_arguments(current, regs, args);
*pid_out = args[0];
uattr = (struct sched_attr __user *)args[1];
/*
* Just copy up to sched_flags, we are not interested after that
*/
ret = copy_struct_from_user(&attr, size, uattr, size);
if (ret)
return ret;
if (attr.sched_flags & SCHED_FLAG_KEEP_POLICY)
return -EINVAL;
new_policy = attr.sched_policy;
break;
default:
return -EINVAL;
}
return new_policy & ~SCHED_RESET_ON_FORK;
}
/* Helper functions requiring DA/HA utilities */
#ifdef RV_MON_TYPE
/*
* get_fair_server - get the fair server associated to a task
*
* If the task is a boosted task, the server is available in the task_struct,
* otherwise grab the dl entity saved for the CPU where the task is enqueued.
* This function assumes the task is enqueued somewhere.
*/
static inline struct sched_dl_entity *get_server(struct task_struct *tsk, u8 type)
{
if (tsk->dl_server && get_server_type(tsk) == type)
return tsk->dl_server;
if (type == DL_SERVER_FAIR)
return da_get_target_by_id(fair_server_id(task_cpu(tsk)));
if (type == DL_SERVER_EXT)
return da_get_target_by_id(ext_server_id(task_cpu(tsk)));
return NULL;
}
/*
* Initialise monitors for all tasks and pre-allocate the storage for servers.
* This is necessary since we don't have access to the servers here and
* allocation can cause deadlocks from their tracepoints. We can only fill
* pre-initialised storage from there.
*/
static inline int init_storage(bool skip_tasks)
{
struct task_struct *g, *p;
int cpu;
for_each_possible_cpu(cpu) {
if (!da_create_empty_storage(fair_server_id(cpu)))
goto fail;
if (IS_ENABLED(CONFIG_SCHED_CLASS_EXT) &&
!da_create_empty_storage(ext_server_id(cpu)))
goto fail;
}
if (skip_tasks)
return 0;
read_lock(&tasklist_lock);
for_each_process_thread(g, p) {
if (p->policy == SCHED_DEADLINE) {
if (!da_create_storage(EXPAND_ID_TASK(p), NULL)) {
read_unlock(&tasklist_lock);
goto fail;
}
}
}
read_unlock(&tasklist_lock);
return 0;
fail:
da_monitor_destroy();
return -ENOMEM;
}
static void __maybe_unused handle_newtask(void *data, struct task_struct *task, u64 flags)
{
/* Might be superfluous as tasks are not started with this policy.. */
if (task->policy == SCHED_DEADLINE)
da_create_storage(EXPAND_ID_TASK(task), NULL);
}
static void __maybe_unused handle_exit(void *data, struct task_struct *p, bool group_dead)
{
if (p->policy == SCHED_DEADLINE)
da_destroy_storage(get_entity_id(&p->dl, DL_TASK, DL_TASK));
}
#endif