From 821306940eca5f9fa25cc1e199457956f3cf3981 Mon Sep 17 00:00:00 2001 From: Hu Zhaodong Date: Thu, 16 Jun 2022 08:47:17 -0700 Subject: [PATCH] sched:Add qos control and qos authority ohos inclusion category: feature issue: #I5IFB2 CVE: NA Signed-off-by: Hu Zhaodong ----------- Support qos manipulate and authority mechanism. Specific threads can apply qos. Kernel will check the authroity, and decides whether applys should take effect according to the status of thread. Signed-off-by: Hu Zhaodong Reviewed-by: Zheng Bin Reviewed-by: Wang Shuo Reviewed-by: Cheng Jian --- include/linux/sched.h | 5 + include/linux/sched/rtg_ctrl.h | 30 ++ init/main.c | 8 + kernel/sched/core.c | 5 + kernel/sched/rtg/Kconfig | 18 ++ kernel/sched/rtg/Makefile | 1 + kernel/sched/rtg/rtg_ctrl.c | 487 ++++++++++++++++++++++++++++++++- kernel/sched/rtg/rtg_ctrl.h | 69 +++++ kernel/sched/rtg/rtg_qos.c | 241 ++++++++++++++++ kernel/sched/rtg/rtg_qos.h | 37 +++ kernel/sched/walt.c | 4 + 11 files changed, 904 insertions(+), 1 deletion(-) create mode 100644 kernel/sched/rtg/rtg_qos.c create mode 100644 kernel/sched/rtg/rtg_qos.h diff --git a/include/linux/sched.h b/include/linux/sched.h index 6ae4d7ae5a3b..4870228ef492 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -817,6 +817,11 @@ struct task_struct { struct list_head grp_list; #endif +#ifdef CONFIG_SCHED_RTG_QOS + struct list_head qos_list; + int in_qos; +#endif + #ifdef CONFIG_CGROUP_SCHED struct task_group *sched_task_group; #endif diff --git a/include/linux/sched/rtg_ctrl.h b/include/linux/sched/rtg_ctrl.h index b71dd74e7fc3..6bd3046e18aa 100644 --- a/include/linux/sched/rtg_ctrl.h +++ b/include/linux/sched/rtg_ctrl.h @@ -42,6 +42,14 @@ _IOWR(RTG_SCHED_IPC_MAGIC, SEARCH_RTG, struct proc_state_data) #define CMD_ID_GET_ENABLE \ _IOWR(RTG_SCHED_IPC_MAGIC, GET_ENABLE, struct rtg_enable_data) +#ifdef CONFIG_SCHED_RTG_AUTHORITY +#define CMD_ID_AUTH_MANIPULATE \ + _IOWR(RTG_SCHED_IPC_MAGIC, AUTH_MANIPULATE, struct rtg_auth_data) +#endif +#ifdef CONFIG_SCHED_RTG_QOS +#define CMD_ID_QOS_MANIPULATE \ + _IOWR(RTG_SCHED_IPC_MAGIC, QOS_MANIPULATE, struct rtg_qos_data) +#endif int proc_rtg_open(struct inode *inode, struct file *filp); long proc_rtg_ioctl(struct file *file, unsigned int cmd, unsigned long arg); @@ -68,6 +76,12 @@ enum rtg_sched_cmdid { LIST_RTG_THREAD, SEARCH_RTG, GET_ENABLE, +#ifdef CONFIG_SCHED_RTG_AUTHORITY + AUTH_MANIPULATE, /* SYSTEM OR ROOT */ +#endif +#ifdef CONFIG_SCHED_RTG_QOS + QOS_MANIPULATE, +#endif RTG_CTRL_MAX_NR, }; @@ -96,4 +110,20 @@ struct proc_state_data { int grp_id; int state_param; }; + +#ifdef CONFIG_SCHED_RTG_AUTHORITY +struct rtg_auth_data { + unsigned int uid; + unsigned int type; + unsigned int ua_flag; + unsigned int status; +}; +#endif + +#ifdef CONFIG_SCHED_RTG_QOS +struct rtg_qos_data { + unsigned int type; + unsigned int level; +}; +#endif #endif diff --git a/init/main.c b/init/main.c index 93364d974eb8..3a87bc79ac20 100644 --- a/init/main.c +++ b/init/main.c @@ -113,6 +113,10 @@ #include +#ifdef CONFIG_SCHED_RTG_AUTHORITY +extern int init_rtg_authority_control(void); +#endif + static int kernel_init(void *); extern void init_IRQ(void); @@ -925,6 +929,10 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void) local_irq_disable(); radix_tree_init(); +#ifdef CONFIG_SCHED_RTG_AUTHORITY + BUG_ON(init_rtg_authority_control()); +#endif + /* * Set up housekeeping before setting up workqueues to allow the unbound * workqueue to take non-housekeeping into account. diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 549334102718..adfacfa58dd0 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -30,6 +30,7 @@ #include "smp.h" #include "walt.h" #include "rtg/rtg.h" +#include "rtg/rtg_qos.h" /* * Export tracepoints that act as a bare tracehook (ie: have no trace event @@ -9076,6 +9077,10 @@ void sched_exit(struct task_struct *p) sched_set_group_id(p, 0); #endif +#ifdef CONFIG_SCHED_RTG_QOS + sched_exit_qos_list(p); +#endif + rq = task_rq_lock(p, &rf); /* rq->curr == p */ diff --git a/kernel/sched/rtg/Kconfig b/kernel/sched/rtg/Kconfig index 1cb0c4298b09..8f556d28a9aa 100644 --- a/kernel/sched/rtg/Kconfig +++ b/kernel/sched/rtg/Kconfig @@ -37,4 +37,22 @@ config SCHED_RTG_RT_THREAD_LIMIT default n help If set, limit the number of RT threads in frame RTG. + +config SCHED_RTG_AUTHORITY + bool "Related Thread Group authority control" + depends on SCHED_RTG + default n + help + Support authority for RTG-related operations. If set, + only thread authorized can do RTG-related operations. + +config SCHED_RTG_QOS + bool "Related Thread Group authority control" + depends on SCHED_RTG + depends on SCHED_RTG_AUTHORITY + default n + help + Introduce qos support for thread. If set, thread can + apply kernel qos for better cpu time supply or lower + latency. endmenu diff --git a/kernel/sched/rtg/Makefile b/kernel/sched/rtg/Makefile index 4d55523d1f32..dd2206e4d61f 100644 --- a/kernel/sched/rtg/Makefile +++ b/kernel/sched/rtg/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SCHED_RTG) += rtg.o obj-$(CONFIG_SCHED_RTG_FRAME) += frame_rtg.o rtg_ctrl.o +obj-$(CONFIG_SCHED_RTG_QOS) += rtg_qos.o diff --git a/kernel/sched/rtg/rtg_ctrl.c b/kernel/sched/rtg/rtg_ctrl.c index d49e02899495..b01e0ab026b2 100644 --- a/kernel/sched/rtg/rtg_ctrl.c +++ b/kernel/sched/rtg/rtg_ctrl.c @@ -7,11 +7,18 @@ #include "rtg.h" #include "rtg_ctrl.h" +#include "rtg_qos.h" #include #include #include #include +#ifdef CONFIG_SCHED_RTG_AUTHORITY +#include +#include +#include +#include +#endif #include atomic_t g_rtg_enable = ATOMIC_INIT(0); @@ -33,6 +40,12 @@ static long ctrl_list_rtg(int abi, void __user *uarg); static long ctrl_list_rtg_thread(int abi, void __user *uarg); static long ctrl_search_rtg(int abi, void __user *uarg); static long ctrl_get_enable(int abi, void __user *uarg); +#ifdef CONFIG_SCHED_RTG_AUTHORITY +static long ctrl_auth_manipulate(int abi, void __user *uarg); +#endif +#ifdef CONFIG_SCHED_RTG_QOS +static long ctrl_qos_manipulate(int abi, void __user *uarg); +#endif static rtg_ctrl_func g_func_array[RTG_CTRL_MAX_NR] = { NULL, /* reserved */ @@ -48,7 +61,13 @@ static rtg_ctrl_func g_func_array[RTG_CTRL_MAX_NR] = { ctrl_list_rtg, // 10 ctrl_list_rtg_thread, ctrl_search_rtg, - ctrl_get_enable + ctrl_get_enable, +#ifdef CONFIG_SCHED_RTG_AUTHORITY + ctrl_auth_manipulate, +#endif +#ifdef CONFIG_SCHED_RTG_QOS + ctrl_qos_manipulate, +#endif }; static int init_proc_state(const int *config, int len); @@ -878,6 +897,462 @@ static long ctrl_search_rtg(int abi, void __user *uarg) return search_rtg(search_data.state_param); } +#ifdef CONFIG_SCHED_RTG_AUTHORITY +/* + * uid-based authority idr table + */ +static struct idr *ua_idr; + +static DEFINE_RAW_SPINLOCK(ua_idr_lock); + +static struct rtg_authority rtg_auth_super; + +static void change_to_super(struct rtg_authority *auth) +{ + auth->flag = AF_RTG_ALL; + auth->status = AUTH_STATUS_ENABLE; +} + +static void init_rtg_authority_record(struct rtg_authority *auth) +{ +#ifdef CONFIG_SCHED_RTG_QOS + int i; +#endif + + auth->flag = 0; + auth->status = AUTH_STATUS_CACHED; + raw_spin_lock_init(&auth->auth_lock); + refcount_set(&auth->usage, 1); +#ifdef CONFIG_SCHED_RTG_QOS + for (i = 0; i <= NR_QOS; ++i) { + INIT_LIST_HEAD(&auth->tasks[i]); + auth->num[i] = 0; + } +#endif +} + +void get_rtg_auth(struct rtg_authority *auth) +{ + refcount_inc(&auth->usage); +} + +#ifdef CONFIG_SCHED_RTG_QOS +static void remove_qos_tasks(struct rtg_authority *auth) +{ + int i; + struct task_struct *tmp, *next; + + for (i = 0; i <= NR_QOS; ++i) { + list_for_each_entry_safe(tmp, next, &auth->tasks[i], qos_list) { + get_task_struct(tmp); + tmp->in_qos = 0; + list_del_init(&tmp->qos_list); + put_task_struct(tmp); + } + } +} +#endif + +static void __put_rtg_auth(struct rtg_authority *auth) +{ + WARN_ON(auth->status != AUTH_STATUS_DEAD); + WARN_ON(refcount_read(&auth->usage)); + +#ifdef CONFIG_SCHED_RTG_QOS + /* refcount is zero here, no contend, no lock. */ + remove_qos_tasks(auth); +#endif + kfree(auth); +} + +void put_rtg_auth(struct rtg_authority *auth) +{ + if (refcount_dec_and_test(&auth->usage)) + __put_rtg_auth(auth); +} + +int init_rtg_authority_control(void) +{ + int ret; + + ua_idr = kzalloc(sizeof(*ua_idr), GFP_ATOMIC); + if (ua_idr == NULL) { + pr_err("[SCHED_RTG] rtg idr init failed, no memory!\n"); + return -ENOMEM; + } + + idr_init(ua_idr); + + init_rtg_authority_record(&rtg_auth_super); + change_to_super(&rtg_auth_super); + + ret = idr_alloc(ua_idr, &rtg_auth_super, UID_FOR_SUPER, UID_FOR_SUPER + 1, GFP_ATOMIC); + if (ret != UID_FOR_SUPER) { + pr_err("[SCHED_RTG] rtg authority for super init failed! ret=%d\n", ret); + goto err; + } + + return 0; + +err: + idr_destroy(ua_idr); + kfree(ua_idr); + + return ret; +} + +int authority_remove_handler(int id, void *p, void *para) +{ + struct rtg_authority *auth = (struct rtg_authority *)p; + + raw_spin_lock(&auth->auth_lock); +#ifdef CONFIG_SCHED_RTG_QOS + qos_pause(auth); +#endif + auth->status = AUTH_STATUS_DEAD; + raw_spin_unlock(&auth->auth_lock); + put_rtg_auth(auth); + + return 0; +} + +void remove_rtg_authority_control(void) +{ + int ret; + + raw_spin_lock(&ua_idr_lock); + ret = idr_for_each(ua_idr, authority_remove_handler, NULL); + if (ret < 0) + pr_err("[SCHED_RTG] rtg authority item remove failed\n"); + + idr_destroy(ua_idr); + kfree(ua_idr); + + raw_spin_unlock(&ua_idr_lock); +} + +static int auth_trim(unsigned int ua_flag) +{ + return ua_flag & AF_RTG_DELEGATED; +} + +static int auth_enable(struct rtg_auth_data *data) +{ + struct rtg_authority *auth_to_enable; + unsigned int uid = data->uid; + bool enable = (data->status == AUTH_STATUS_ENABLE); + int ret; + + raw_spin_lock(&ua_idr_lock); + auth_to_enable = idr_find(ua_idr, uid); + /* auth exist, just resume the task's qos request */ + if (auth_to_enable) { + get_rtg_auth(auth_to_enable); + raw_spin_unlock(&ua_idr_lock); + + raw_spin_lock(&auth_to_enable->auth_lock); + if (auth_to_enable->status == AUTH_STATUS_DEAD) { + raw_spin_unlock(&auth_to_enable->auth_lock); + put_rtg_auth(auth_to_enable); + return -INVALID_AUTH; + } + + auth_to_enable->flag = auth_trim(data->ua_flag); +#ifdef CONFIG_SCHED_RTG_QOS + if (enable) + qos_resume(auth_to_enable); +#endif + raw_spin_unlock(&auth_to_enable->auth_lock); + ret = 0; + put_rtg_auth(auth_to_enable); + goto out; + } + + /* auth not exist, build a new auth, then insert to idr */ + auth_to_enable = kzalloc(sizeof(*auth_to_enable), GFP_ATOMIC); + if (!auth_to_enable) { + raw_spin_unlock(&ua_idr_lock); + pr_err("[SCHED_RTG] alloc auth data failed, no memory!\n"); + ret = -ENOMEM; + goto out; + } + + init_rtg_authority_record(auth_to_enable); + + /* no one could get the auth from idr now, no need to lock */ + auth_to_enable->flag = auth_trim(data->ua_flag); + if (enable) + auth_to_enable->status = AUTH_STATUS_ENABLE; + + ret = idr_alloc(ua_idr, auth_to_enable, uid, uid + 1, GFP_ATOMIC); + if (ret < 0) { + pr_err("[SCHED_RTG] add auth to idr failed, no memory!\n"); + kfree(auth_to_enable); + } + + raw_spin_unlock(&ua_idr_lock); + +out: + return ret; +} + +static int auth_pause(struct rtg_auth_data *data) +{ + struct rtg_authority *auth_to_pause; + unsigned int uid = data->uid; + + raw_spin_lock(&ua_idr_lock); + auth_to_pause = idr_find(ua_idr, uid); + if (!auth_to_pause) { + raw_spin_unlock(&ua_idr_lock); + pr_err("[SCHED_RTG] no auth data for this uid to pause=%d\n", uid); + return UID_NOT_FOUND; + } + get_rtg_auth(auth_to_pause); + raw_spin_unlock(&ua_idr_lock); + + raw_spin_lock(&auth_to_pause->auth_lock); + if (auth_to_pause->status == AUTH_STATUS_DEAD) { + raw_spin_unlock(&auth_to_pause->auth_lock); + put_rtg_auth(auth_to_pause); + return -INVALID_AUTH; + } +#ifdef CONFIG_SCHED_RTG_QOS + qos_pause(auth_to_pause); +#endif + raw_spin_unlock(&auth_to_pause->auth_lock); + + put_rtg_auth(auth_to_pause); + + return 0; +} + +static int auth_delete(struct rtg_auth_data *data) +{ + struct rtg_authority *auth_to_delete; + unsigned int uid = data->uid; + + raw_spin_lock(&ua_idr_lock); + auth_to_delete = (struct rtg_authority *)idr_remove(ua_idr, uid); + if (!auth_to_delete) { + raw_spin_unlock(&ua_idr_lock); + pr_err("[SCHED_RTG] no auth data for this uid=%d, delete failed\n", uid); + return -UID_NOT_FOUND; + } + raw_spin_unlock(&ua_idr_lock); + + raw_spin_lock(&auth_to_delete->auth_lock); +#ifdef CONFIG_SCHED_RTG_QOS + qos_pause(auth_to_delete); +#endif + auth_to_delete->status = AUTH_STATUS_DEAD; + raw_spin_unlock(&auth_to_delete->auth_lock); + + put_rtg_auth(auth_to_delete); + + return 0; +} + +static int auth_get(struct rtg_auth_data *data) +{ + struct rtg_authority *auth_to_get; + unsigned int uid = data->uid; + + raw_spin_lock(&ua_idr_lock); + auth_to_get = idr_find(ua_idr, uid); + if (!auth_to_get) { + raw_spin_unlock(&ua_idr_lock); + pr_err("[SCHED_RTG] no auth data for this uid=%d to get\n", uid); + return -UID_NOT_FOUND; + } + get_rtg_auth(auth_to_get); + raw_spin_unlock(&ua_idr_lock); + + raw_spin_lock(&auth_to_get->auth_lock); + if (auth_to_get->status == AUTH_STATUS_DEAD) { + raw_spin_unlock(&auth_to_get->auth_lock); + put_rtg_auth(auth_to_get); + return -INVALID_AUTH; + } + data->ua_flag = auth_to_get->flag; + data->status = auth_to_get->status; + raw_spin_unlock(&auth_to_get->auth_lock); + + put_rtg_auth(auth_to_get); + + return 0; +} + +typedef int (*rtg_auth_manipulate_func)(struct rtg_auth_data *data); + +static rtg_auth_manipulate_func auth_func_array[AUTH_MAX_NR] = { + NULL, + auth_enable, //1 + auth_pause, + auth_delete, + auth_get, +}; + +static long do_auth_manipulate(struct rtg_auth_data *data) +{ + long ret = 0; + unsigned int type = data->type; + + if (type >= AUTH_MAX_NR) { + pr_err("[SCHED_RTG] CMD_ID_AUTH_MANIPULATE type not valid\n"); + return -INVALID_ARG; + } + + if (auth_func_array[type]) + ret = (long)(*auth_func_array[type])(data); + + return ret; +} + +static long ctrl_auth_manipulate(int abi, void __user *uarg) +{ + struct rtg_auth_data auth_data; + long ret; + + if (copy_from_user(&auth_data, uarg, sizeof(struct rtg_auth_data))) { + pr_err("[SCHED_RTG] CMD_ID_AUTH_MANIPULATE copy data failed\n"); + return -INVALID_ARG; + } + + ret = do_auth_manipulate(&auth_data); + if (ret < 0) { + pr_err("[SCHED_RTG]] CMD_ID_AUTH_MANIPULATE failed\n"); + return ret; + } + + if (copy_to_user(uarg, &auth_data, sizeof(struct rtg_auth_data))) { + pr_err("[SCHED_RTG]] CMD_ID_AUTH_MANIPULATE send data failed\n"); + return -INVALID_ARG; + } + + return 0; +} + +#define get_authority_flag(func_id) (1 << (func_id - 1)) + +static inline unsigned int get_true_uid(struct task_struct *p) +{ + if (!p) + return get_uid(current_user())->uid.val; + + return task_uid(p).val; +} + +/* + * Return 1000 for both SYSTEM and ROOT + */ +static inline unsigned int get_authority_uid(struct task_struct *p) +{ + unsigned int uid = get_true_uid(p); + + if (super_uid(uid)) + uid = UID_FOR_SUPER; + + return uid; +} + +static bool rtg_check_authorized(unsigned int func_id) +{ + bool authorized = false; + struct rtg_authority *auth; + unsigned int af = get_authority_flag(func_id); + unsigned int uid = get_authority_uid(NULL); + + raw_spin_lock(&ua_idr_lock); + if (!ua_idr) { + raw_spin_unlock(&ua_idr_lock); + pr_err("[SCHED_RTG] authority idr table missed, auth failed\n"); + return authorized; + } + + auth = (struct rtg_authority *)idr_find(ua_idr, uid); + if (!auth) { + raw_spin_unlock(&ua_idr_lock); + pr_err("[SCHED_RTG] no auth data for this uid=%d\n", uid); + return authorized; + } + get_rtg_auth(auth); + raw_spin_unlock(&ua_idr_lock); + + raw_spin_lock(&auth->auth_lock); + if (auth->status == AUTH_STATUS_DEAD) { + raw_spin_unlock(&auth->auth_lock); + pr_info("[SCHED_RTG] not valied auth for uid %d\n", uid); + put_rtg_auth(auth); + return authorized; + } + if (auth && (auth->flag & af)) + authorized = true; + + raw_spin_unlock(&auth->auth_lock); + + put_rtg_auth(auth); + + return authorized; +} + +/* + * Return RTG authority info for given task + * return current's auth if p is NULL + * recount will inc if this call return the valid auth + * make sure to call put_rtg_auth before the calling end + */ +struct rtg_authority *get_authority(struct task_struct *p) +{ + unsigned int uid = get_authority_uid(NULL); + struct rtg_authority *auth; + + raw_spin_lock(&ua_idr_lock); + auth = idr_find(ua_idr, uid); + if (auth) + get_rtg_auth(auth); + raw_spin_unlock(&ua_idr_lock); + + return auth; +} + +#ifdef CONFIG_SCHED_RTG_QOS +static rtg_qos_manipulate_func qos_func_array[QOS_MAX_NR] = { + NULL, + qos_apply, //1 + qos_leave, +}; + +static long do_qos_manipulate(struct rtg_qos_data *data) +{ + long ret = 0; + unsigned int type = data->type; + + if (type >= QOS_MAX_NR) { + pr_err("[SCHED_RTG] CMD_ID_QOS_MANIPULATE type not valid\n"); + return -INVALID_ARG; + } + + if (qos_func_array[type]) + ret = (long)(*qos_func_array[type])(data); + + return ret; +} + +static long ctrl_qos_manipulate(int abi, void __user *uarg) +{ + struct rtg_qos_data qos_data; + + if (copy_from_user(&qos_data, uarg, sizeof(struct rtg_qos_data))) { + pr_err("[SCHED_RTG] CMD_ID_QOS_APPLY copy data failed\n"); + return -INVALID_ARG; + } + + return do_qos_manipulate(&qos_data); +} +#endif +#endif /* CONFIG_SCHED_RTG_AUTHORITY */ + static long do_proc_rtg_ioctl(int abi, struct file *file, unsigned int cmd, unsigned long arg) { void __user *uarg = (void __user *)(uintptr_t)arg; @@ -888,6 +1363,13 @@ static long do_proc_rtg_ioctl(int abi, struct file *file, unsigned int cmd, unsi return -EINVAL; } +#ifdef CONFIG_SCHED_RTG_AUTHORITY + if (!rtg_check_authorized(func_id)) { + pr_err("[SCHED_RTG] %s: uid not authorized\n", __func__); + return -UID_NOT_AUTHORIZED; + } +#endif + if (_IOC_TYPE(cmd) != RTG_SCHED_IPC_MAGIC) { pr_err("[SCHED_RTG] %s: RTG_SCHED_IPC_MAGIC fail, TYPE=%d\n", __func__, _IOC_TYPE(cmd)); @@ -1049,6 +1531,9 @@ static int __init rtg_ctrl_dev_init(void) static void __exit rtg_ctrl_dev_exit(void) { misc_deregister(&rtg_ctrl_device); +#ifdef CONFIG_SCHED_RTG_AUTHORITY + remove_rtg_authority_control(); +#endif } module_init(rtg_ctrl_dev_init); diff --git a/kernel/sched/rtg/rtg_ctrl.h b/kernel/sched/rtg/rtg_ctrl.h index 6d405f589dab..6f8db6426464 100644 --- a/kernel/sched/rtg/rtg_ctrl.h +++ b/kernel/sched/rtg/rtg_ctrl.h @@ -11,8 +11,13 @@ #include #include #include +#ifdef CONFIG_SCHED_RTG_AUTHORITY +#include +#include +#endif #include "frame_rtg.h" +#include "rtg_qos.h" /* set rtg */ #define INVALID_VALUE 0xffff @@ -36,6 +41,50 @@ #define MAX_FREQ_CYCLE 16 #define DEFAULT_INVALID_INTERVAL 50 + +#ifdef CONFIG_SCHED_RTG_AUTHORITY +/* + * RTG authority flags for SYSTEM or ROOT + * + * keep sync with rtg_sched_cmdid + * when add a new cmd to rtg_sched_cmdid + * keep new_flag = (old_flag << 1) + 1 + * up to now, next flag value is 0xbfff + */ +#define AF_RTG_ALL 0x7fff + +/* + * delegated authority for normal uid + * no AUTH_MANIPULATE (rtg_sched_cmdid = 14) + */ +#define AF_RTG_DELEGATED 0x5fff + +#define ROOT_UID 0 +#define SYSTEM_UID 1000 + +#define UID_FOR_SUPER SYSTEM_UID +#define super_uid(uid) (uid == ROOT_UID || uid == SYSTEM_UID) + +enum auth_manipulate_type { + AUTH_ENABLE = 1, + AUTH_PAUSE, + AUTH_DELETE, + AUTH_GET, + AUTH_MAX_NR, +}; + +enum rtg_auth_status { + AUTH_STATUS_CACHED = 0, + AUTH_STATUS_ENABLE, + AUTH_STATUS_DEAD, +}; + +extern int init_rtg_authority_control(void); +struct rtg_authority *get_authority(struct task_struct *p); +void get_rtg_auth(struct rtg_authority *auth); +void put_rtg_auth(struct rtg_authority *auth); +#endif + /* proc_state */ enum proc_state { STATE_MIN = 0, @@ -66,6 +115,13 @@ enum rtg_err_no { NOT_MULTI_FRAME, INVALID_RTG_ID, NO_RT_FRAME, +#ifdef CONFIG_SCHED_RTG_AUTHORITY + UID_NOT_AUTHORIZED, + UID_NOT_FOUND, + PID_DUPLICATE, + PID_NOT_EXIST, + INVALID_AUTH, +#endif }; struct rtg_grp_data { @@ -84,4 +140,17 @@ struct rtg_proc_data { int rtcnt; }; +#ifdef CONFIG_SCHED_RTG_AUTHORITY +struct rtg_authority { + raw_spinlock_t auth_lock; + refcount_t usage; + unsigned int status; + unsigned int flag; +#ifdef CONFIG_SCHED_RTG_QOS + unsigned int num[NR_QOS + 1]; + struct list_head tasks[NR_QOS + 1]; +#endif +}; +#endif + #endif diff --git a/kernel/sched/rtg/rtg_qos.c b/kernel/sched/rtg/rtg_qos.c new file mode 100644 index 000000000000..6cdcac14c1b0 --- /dev/null +++ b/kernel/sched/rtg/rtg_qos.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rtg control entry + * + * Copyright (c) 2022-2023 Huawei Technologies Co., Ltd. + */ +#include "rtg.h" +#include "rtg_ctrl.h" +#include "rtg_qos.h" + +/* + * Pause uid-own-tasks' qos supply + * Called after get auth->auth_lock + */ +void qos_pause(struct rtg_authority *auth) +{ + int i; + struct task_struct *task; + + if (auth->status == AUTH_STATUS_ENABLE) { + for (i = 0; i <= NR_QOS; ++i) { + list_for_each_entry(task, &auth->tasks[i], qos_list) { + /* remove_latency_nice || remove_from_rtg_nocheck*/ + /* what if reset failed on some task ? */ + } + } + } + + auth->status = AUTH_STATUS_CACHED; +} + +/* + * Resume uid-own-tasks' qos supply + * Called after get auth->auth_lock + */ +void qos_resume(struct rtg_authority *auth) +{ + int i; + struct task_struct *task; + + if (!auth) { + pr_err("[SCHED_RTG] auth no exist, qos resume failed\n"); + return; + } + + if (auth->status == AUTH_STATUS_CACHED) { + for (i = 0; i <= NR_QOS; ++i) { + list_for_each_entry(task, &auth->tasks[i], qos_list) { + /* add_latency_nice || add_to_rtg_nocheck */ + /* what if resume failed on some task ? */ + } + } + } +} + +static int insert_task(struct task_struct *p, struct list_head *head, unsigned int level) +{ + if (p->in_qos) { + pr_err("[SCHED_RTG] qos apply request has cached, duplicate add\n"); + return -PID_DUPLICATE; + } + + list_add(&p->qos_list, head); + p->in_qos = level; + + return 0; +} + +static int remove_task(struct task_struct *p) +{ + if (!p->in_qos) { + pr_err("[SCHED_RTG] qos apply request not cached, stop failed\n"); + return -PID_NOT_EXIST; + } + + list_del_init(&p->qos_list); + p->in_qos = 0; + + return 0; +} + +int qos_apply(struct rtg_qos_data *data) +{ + unsigned int level = data->level; + struct rtg_authority *auth; + int ret; + + if (level > NR_QOS || level == 0) { + pr_err("[SCHED_RTG] no this qos level, qos apply failed\n"); + ret = -INVALID_ARG; + goto out; + } + + auth = get_authority(NULL); + if (!auth) { + pr_err("[SCHED_RTG] no auth data for pid=%d(%s) this uid=%d, qos apply failed\n", + current->pid, current->comm, current->cred->uid.val); + return -UID_NOT_FOUND; + } + + raw_spin_lock(&auth->auth_lock); + if (auth->status == AUTH_STATUS_DEAD) { + pr_err("[SCHED_RTG] this auth data has been deleted\n"); + ret = -INVALID_AUTH; + goto out_unlock; + } + + if (auth->num[level] >= RTG_QOS_NUM_MAX) { + pr_notice("[SCHED_RTG] qos num exceeds limit, cached only\n"); + ret = 0; + goto out_unlock; + } + + ret = insert_task(current, &auth->tasks[level], level); + if (ret < 0) + goto out_unlock; + + ++auth->num[level]; + + if (auth->status == AUTH_STATUS_ENABLE) { + switch (level) { + case 5: + /* add_to_rtg_nocheck*/ + break; + case 4: + /* add_to_latency_nice */ + break; + default: + break; + } + } + + ret = 0; + +out_unlock: + raw_spin_unlock(&auth->auth_lock); + put_rtg_auth(auth); +out: + return ret; +} + +int qos_leave(struct rtg_qos_data *data) +{ + unsigned int level; + struct rtg_authority *auth; + int ret; + + auth = get_authority(NULL); + if (!auth) { + pr_err("[SCHED_RTG] no auth data for pid=%d(%s) this uid=%d, qos stop failed\n", + current->pid, current->comm, current->cred->uid.val); + ret = -UID_NOT_FOUND; + } + + raw_spin_lock(&auth->auth_lock); + level = current->in_qos; + if (level == 0) { + pr_err("[SCHED_RTG] no this qos level, qos stop failed\n"); + ret = -INVALID_ARG; + goto out_unlock; + } + + if (auth->status == AUTH_STATUS_DEAD) { + pr_err("[SCHED_RTG] this auth data has been deleted\n"); + ret = -INVALID_AUTH; + goto out_unlock; + } + + ret = remove_task(current); + if (ret < 0) + goto out_unlock; + + --auth->num[level]; + + if (auth->status == AUTH_STATUS_ENABLE) { + switch (level) { + case 5: + /* remove_from_rtg_nocheck*/ + break; + case 4: + /* remove_latency_nice */ + break; + default: + break; + } + } + + ret = 0; + +out_unlock: + raw_spin_unlock(&auth->auth_lock); + put_rtg_auth(auth); + + return ret; +} + +void init_task_qos(struct task_struct *p) +{ + INIT_LIST_HEAD(&p->qos_list); + p->in_qos = 0; +} + +/* + * Remove statistic info in auth when task exit + */ +void sched_exit_qos_list(struct task_struct *p) +{ + struct rtg_authority *auth; + + /* + * For common tasks(the vast majority): + * skip get authority, fast return here. + * + * For qos tasks: + * If contend with auth_delete() happens, + * 1. function return here, auth_delete() will do the clean up + * 2. function go on, either no auth return, either do clean up here + * Both cases guarantee data synchronization + */ + if (likely(!p->in_qos)) + return; + + auth = get_authority(p); + if (!auth) + goto out; + + raw_spin_lock(&auth->auth_lock); + if (!p->in_qos) { + raw_spin_unlock(&auth->auth_lock); + goto out_put_auth; + } + --auth->num[p->in_qos]; + list_del_init(&p->qos_list); + p->in_qos = 0; + raw_spin_unlock(&auth->auth_lock); + +out_put_auth: + put_rtg_auth(auth); +out: + return; +} diff --git a/kernel/sched/rtg/rtg_qos.h b/kernel/sched/rtg/rtg_qos.h new file mode 100644 index 000000000000..af92efe4a861 --- /dev/null +++ b/kernel/sched/rtg/rtg_qos.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rtg qos interface + * + * Copyright (c) 2022-2023 Huawei Technologies Co., Ltd. + */ + +#ifndef __RTG_QOS_H +#define __RTG_QOS_H + +#ifdef CONFIG_SCHED_RTG_QOS +#include + +enum qos_manipulate_type { + QOS_APPLY = 1, + QOS_LEAVE, + QOS_MAX_NR, +}; + +#define NR_QOS 5 +#define RTG_QOS_NUM_MAX 10 + +struct rtg_authority; + +int qos_apply(struct rtg_qos_data *data); +int qos_leave(struct rtg_qos_data *data); + +void qos_pause(struct rtg_authority *auth); +void qos_resume(struct rtg_authority *auth); + +void init_task_qos(struct task_struct *p); +void sched_exit_qos_list(struct task_struct *p); + +typedef int (*rtg_qos_manipulate_func)(struct rtg_qos_data *data); +#endif + +#endif /* __RTG_QOS_H */ diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 8d4c79028d8a..b7be4d8723f4 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -25,6 +25,7 @@ #include "walt.h" #include "core_ctl.h" #include "rtg/rtg.h" +#include "rtg/rtg_qos.h" #define CREATE_TRACE_POINTS #include #undef CREATE_TRACE_POINTS @@ -1237,6 +1238,9 @@ void init_new_task_load(struct task_struct *p) #ifdef CONFIG_SCHED_RTG init_task_rtg(p); #endif +#ifdef CONFIG_SCHED_RTG_QOS + init_task_qos(p); +#endif p->last_sleep_ts = 0; p->init_load_pct = 0; -- Gitee