sched: add qos ctrl and authority ctrl for FFRT

ohos inclusion
category: feature
issue: #I76RYD
CVE:NA

Signed-off-by: Huzhaodong <huzhaodong@huawei.com>
This commit is contained in:
Huzhaodong
2023-05-21 08:38:27 -07:00
committed by wanxiaoqing40281
parent af27f4af85
commit 90dc7a386f
17 changed files with 1966 additions and 0 deletions
+1
View File
@@ -1,5 +1,6 @@
(1) The directories below are licensed under GPL-2.0-or-later.
./newip/
./xpm/
./qos_auth/
As for the specific use of the licenses, please refer to the relevant description in the documents.
+3
View File
@@ -59,8 +59,10 @@ Note:If the text contains special characters, please escape them according to th
<policy name="newipPolicy" desc="New IP protocol stack">
<policyitem type="compatibility" name="GPL" path="newip/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="qos_auth/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="newip/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="qos_auth/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
</policy>
</policylist>
<filefilterlist>
@@ -78,6 +80,7 @@ Note:If the text contains special characters, please escape them according to th
<filefilter name="binaryFileTypePolicyFilter" desc="binary file filter">
<filteritem type="filepath" name="newip/figures/.*"/>
<filteritem type="filepath" name="xpm/figures/.*"/>
<filteritem type="filepath" name="qos_auth/figures/.*"/>
</filefilter>
</filefilterlist>
</oatconfig>
+71
View File
@@ -0,0 +1,71 @@
## 背景
为支持并发编程框架FFRT的底层调度能力而设计,允许app侧根据业务逻辑在线程间分配调度资源,保障关键任务时延达标,保障用户体验。
涉及到权限下放和调度资源分配,需要内核实现:
1. 高效的能感知状态的app权限管控机制(轻量化权限管控)
2. 动态的调度资源分配机制(动态多级qos)
## auth_ctrl(Authority Control)模块
轻量化权限管控模块,uid粒度的权限管控,根据app前后台状态动态管控对内核feature接口的访问权限
![轻量化权限管控架构](figures/轻量化权限管控架构.png)
## qos_ctrl(Qos Control)模块
动态多级qos模块,提供多种policy(前台/后台/system等),每个policy包含6个qos等级,可以从时间片、调度时延、供给3个维度去更改线程调度行为
![多级qos架构图](figures/多级qos架构图.png)
## 目录
```
├── README_zh.md
├── apply_qos_auth.sh
├── figures # ReadMe 内嵌图例
├── auth_ctl
│ ├── Kconfig
│ ├── Makefile
│ ├── auth_ctrl.c #权限管控主体代码
│ ├── auth_ctrl.h
│ ├── auth_qos_debug.c #debug节点主体
│ ├── qos_ctrl.c #多级qos主体代码
│ └── qos_ctrl.h
└── include
├── auth_ctrl.h
├── qos_auth.h
├── qos_ctrl.h
└── rtg_auth.h
```
## QOS_AUTH配置指导
1. 权限管控使能`CONFIG_AUTHORITY_CTRL=y`
2. 多级qos使能`CONFIG_QOS_CTRL=y`
3. RTG鉴权使能`CONFIG_RTG_AUTHORITY=y`
4. qos鉴权使能`CONFIG_QOS_AUTHORITY=y`
5. Debug节点使能`CONFIG_AUTH_QOS_DEBUG=y`
6. Qos策略数量限制`CONFIG_QOS_POLICY_MAX_NR=5`,范围[5, 20]
qos成功设置的宏依赖:
```
# 时延控制
CONFIG_SCHED_LATENCY_NICE=y
# 供给
CONFIG_UCLAMP_TASK=y
CONFIG_UCLAMP_BUCKETS_COUNT=20
CONFIG_UCLAMP_TASK_GROUP=y
```
## 相关仓
[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10)
[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config)
[device_board_hihope](https://gitee.com/openharmony/device_board_hihope)https://gitee.com/openharmony/device_board_hihope)
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2023 Huawei Device Co., Ltd.
#
set -e
OHOS_SOURCE_ROOT=$1
KERNEL_BUILD_ROOT=$2
PRODUCT_NAME=$3
KERNEL_VERSION=$4
QOS_AUTH_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/qos_auth
function main()
{
pushd .
cd $KERNEL_BUILD_ROOT/include/linux/sched
ln -sf $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/linux/sched $QOS_AUTH_SOURCE_ROOT/include)/*.h ./
if [ ! -d "$KERNEL_BUILD_ROOT/drivers/auth_ctl" ]; then
mkdir $KERNEL_BUILD_ROOT/drivers/auth_ctl
fi
cd $KERNEL_BUILD_ROOT/drivers/auth_ctl
ln -sf $(realpath --relative-to=$KERNEL_BUILD_ROOT/drivers/auth_ctl $QOS_AUTH_SOURCE_ROOT/auth_ctl)/* ./
popd
}
main
+55
View File
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-2.0
config AUTHORITY_CTRL
tristate "Authority Control for RTG & QOS"
default n
help
Control thread's authority for specific kenrel feature such as RTG
or QOS. Use uid as the authentication granularity. Status switching
will change uid's authority, and would trigger additional actions
registered by specific kernel feature.
config QOS_CTRL
bool "Multiple Level Qos Control for thread"
default n
depends on AUTHORITY_CTRL
help
If set, thread can apply qos for less execution latency and get more
cpu supply. Permission and absolute supply aggressiveness was controlled
by AUTHORITY_CTRL.
config RTG_AUTHORITY
bool "Authority Control for SCHED_RTG_FRAME"
default n
depends on AUTHORITY_CTRL
depends on SCHED_RTG_FRAME
help
Authority control for SCHED_RTG_FRAME. If set, access to SCHED_RTG_FRAME's
ioctl cmd will be restricted.
config QOS_AUTHORITY
bool "Authority Control for QOS_CTRL"
default n
depends on AUTHORITY_CTRL
depends on QOS_CTRL
help
Authority control for QOS_CTRL. If set, access to QOS_CTRL's ioctl cmd will
be restricted.
config AUTH_QOS_DEBUG
bool "Debug fs for qos_ctrl and auth_ctrl"
default n
depends on AUTHORITY_CTRL
depends on RTG_AUTHORITY
depends on QOS_AUTHORITY
help
If set, debug node will show auth and qos info
config QOS_POLICY_MAX_NR
int "Number of supported qos policy"
range 5 20
default 5
depends on QOS_CTRL
help
Qos policy number limit. Truly initialized qos policy could small then
this value.
+5
View File
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_AUTHORITY_CTRL) += auth_qos_ctrl.o
auth_qos_ctrl-$(CONFIG_AUTHORITY_CTRL) += auth_ctrl.o
auth_qos_ctrl-$(CONFIG_QOS_CTRL) += qos_ctrl.o
auth_qos_ctrl-$(CONFIG_AUTH_QOS_DEBUG) += auth_qos_debug.o
+588
View File
@@ -0,0 +1,588 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/auth_ctl/auth_ctrl.c
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*
*/
#include <linux/cred.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/sched/auth_ctrl.h>
#include <linux/sched/rtg_auth.h>
#include <linux/sched/qos_ctrl.h>
#include <linux/sched/qos_auth.h>
#include "auth_ctrl.h"
#ifdef CONFIG_QOS_CTRL
#include "qos_ctrl.h"
#endif
typedef long (*auth_ctrl_func)(struct file *file, void __user *arg);
static long ctrl_auth_basic_operation(struct file *file, void __user *uarg);
static auth_ctrl_func g_func_array[AUTH_CTRL_MAX_NR] = {
NULL, /* reserved */
ctrl_auth_basic_operation,
};
/*
* uid-based authority idr table
*/
static struct idr *ua_idr;
struct idr *get_auth_ctrl_idr(void)
{
return ua_idr;
}
static DEFINE_MUTEX(ua_idr_mutex);
struct mutex *get_auth_idr_mutex(void)
{
return &ua_idr_mutex;
}
static struct auth_struct auth_super;
/*
* change auth's status to SYSTEM and enable all feature access
*/
static void change_to_super(struct auth_struct *auth)
{
#ifdef CONFIG_RTG_AUTHORITY
auth->rtg_auth_flag = AF_RTG_ALL;
#endif
#ifdef CONFIG_QOS_AUTHORITY
auth->qos_auth_flag = AF_QOS_ALL;
#endif
auth->status = AUTH_STATUS_SYSTEM_SERVER;
}
static void init_authority_record(struct auth_struct *auth)
{
#ifdef CONFIG_QOS_AUTHORITY
int i;
#endif
#ifdef CONFIG_RTG_AUTHORITY
auth->rtg_auth_flag = 0;
#endif
#ifdef CONFIG_QOS_AUTHORITY
auth->qos_auth_flag = 0;
#endif
auth->status = AUTH_STATUS_DISABLED;
mutex_init(&auth->mutex);
refcount_set(&auth->usage, 1);
#ifdef CONFIG_QOS_CTRL
for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
INIT_LIST_HEAD(&auth->tasks[i]);
auth->num[i] = 0;
}
#endif
}
void get_auth_struct(struct auth_struct *auth)
{
refcount_inc(&auth->usage);
}
static void __put_auth_struct(struct auth_struct *auth)
{
WARN_ON(auth->status != AUTH_STATUS_DEAD);
WARN_ON(refcount_read(&auth->usage));
#ifdef CONFIG_QOS_CTRL
/* refcount is zero here, no contend, no lock. */
remove_qos_tasks(auth);
#endif
kfree(auth);
}
void put_auth_struct(struct auth_struct *auth)
{
if (refcount_dec_and_test(&auth->usage))
__put_auth_struct(auth);
}
static int init_authority_control(void)
{
int ret;
ua_idr = kzalloc(sizeof(*ua_idr), GFP_ATOMIC);
if (ua_idr == NULL) {
pr_err("[AUTH_CTRL] auth idr init failed, no memory!\n");
return -ENOMEM;
}
idr_init(ua_idr);
init_authority_record(&auth_super);
change_to_super(&auth_super);
ret = idr_alloc(ua_idr, &auth_super, SUPER_UID, SUPER_UID + 1, GFP_ATOMIC);
if (ret != SUPER_UID) {
pr_err("[AUTH_CTRL] 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 auth_struct *auth = (struct auth_struct *)p;
mutex_lock(&auth->mutex);
#ifdef CONFIG_QOS_CTRL
qos_switch(auth, AUTH_STATUS_DISABLED);
#endif
auth->status = AUTH_STATUS_DEAD;
mutex_unlock(&auth->mutex);
put_auth_struct(auth);
return 0;
}
void remove_authority_control(void)
{
int ret;
mutex_lock(&ua_idr_mutex);
ret = idr_for_each(ua_idr, authority_remove_handler, NULL);
if (ret < 0)
pr_err("[AUTH_CTRL] authority item remove failed\n");
idr_destroy(ua_idr);
kfree(ua_idr);
mutex_unlock(&ua_idr_mutex);
}
/*
* constrain user assigned auth_flag to kernel accepted auth_flag
*/
static int generic_auth_trim(unsigned int orig_flag, unsigned int constrain)
{
return orig_flag & constrain;
}
static inline void set_auth_flag(struct auth_ctrl_data *data, struct auth_struct *auth_to_enable)
{
#ifdef CONFIG_RTG_AUTHORITY
auth_to_enable->rtg_auth_flag = generic_auth_trim(data->rtg_ua_flag, AF_RTG_DELEGATED);
#endif
#ifdef CONFIG_QOS_AUTHORITY
auth_to_enable->qos_auth_flag = generic_auth_trim(data->qos_ua_flag, AF_QOS_ALL);
#endif
}
static int auth_enable(struct auth_ctrl_data *data)
{
struct auth_struct *auth_to_enable;
unsigned int uid = data->uid;
int status = data->status;
int ret;
mutex_lock(&ua_idr_mutex);
auth_to_enable = idr_find(ua_idr, uid);
/* auth exist, just resume the task's qos request */
if (auth_to_enable) {
get_auth_struct(auth_to_enable);
mutex_unlock(&ua_idr_mutex);
mutex_lock(&auth_to_enable->mutex);
if (auth_to_enable->status == AUTH_STATUS_DEAD) {
mutex_unlock(&auth_to_enable->mutex);
put_auth_struct(auth_to_enable);
return -INVALID_AUTH;
}
set_auth_flag(data, auth_to_enable);
#ifdef CONFIG_QOS_CTRL
qos_switch(auth_to_enable, status);
#endif
auth_to_enable->status = status;
mutex_unlock(&auth_to_enable->mutex);
ret = 0;
put_auth_struct(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) {
mutex_unlock(&ua_idr_mutex);
pr_err("[AUTH_CTRL] alloc auth data failed, no memory!\n");
ret = -ENOMEM;
goto out;
}
init_authority_record(auth_to_enable);
/* no one could get the auth from idr now, no need to lock */
set_auth_flag(data, auth_to_enable);
auth_to_enable->status = status;
ret = idr_alloc(ua_idr, auth_to_enable, uid, uid + 1, GFP_ATOMIC);
if (ret < 0) {
pr_err("[AUTH_CTRL] add auth to idr failed, no memory!\n");
kfree(auth_to_enable);
}
mutex_unlock(&ua_idr_mutex);
out:
return ret;
}
static int auth_delete(struct auth_ctrl_data *data)
{
struct auth_struct *auth_to_delete;
unsigned int uid = data->uid;
mutex_lock(&ua_idr_mutex);
auth_to_delete = (struct auth_struct *)idr_remove(ua_idr, uid);
if (!auth_to_delete) {
mutex_unlock(&ua_idr_mutex);
pr_err("[AUTH_CTRL] no auth data for this uid=%d, delete failed\n", uid);
return -UID_NOT_FOUND;
}
mutex_unlock(&ua_idr_mutex);
mutex_lock(&auth_to_delete->mutex);
#ifdef CONFIG_QOS_CTRL
qos_switch(auth_to_delete, AUTH_STATUS_DISABLED);
#endif
auth_to_delete->status = AUTH_STATUS_DEAD;
mutex_unlock(&auth_to_delete->mutex);
put_auth_struct(auth_to_delete);
return 0;
}
static int auth_get(struct auth_ctrl_data *data)
{
struct auth_struct *auth_to_get;
unsigned int uid = data->uid;
mutex_lock(&ua_idr_mutex);
auth_to_get = idr_find(ua_idr, uid);
if (!auth_to_get) {
mutex_unlock(&ua_idr_mutex);
pr_err("[AUTH_CTRL] no auth data for this uid=%d to get\n", uid);
return -UID_NOT_FOUND;
}
get_auth_struct(auth_to_get);
mutex_unlock(&ua_idr_mutex);
mutex_lock(&auth_to_get->mutex);
if (auth_to_get->status == AUTH_STATUS_DEAD) {
mutex_unlock(&auth_to_get->mutex);
put_auth_struct(auth_to_get);
return -INVALID_AUTH;
}
#ifdef CONFIG_RTG_AUTHORITY
data->rtg_ua_flag = auth_to_get->rtg_auth_flag;
#endif
#ifdef CONFIG_QOS_AUTHORITY
data->qos_ua_flag = auth_to_get->qos_auth_flag;
#endif
data->status = auth_to_get->status;
mutex_unlock(&auth_to_get->mutex);
put_auth_struct(auth_to_get);
return 0;
}
static int auth_switch(struct auth_ctrl_data *data)
{
struct auth_struct *auth;
unsigned int uid = data->uid;
unsigned int status = data->status;
if (status == 0 || status >= AUTH_STATUS_MAX_NR) {
pr_err("[AUTH_CTRL] not valied status %d\n", status);
return -ARG_INVALID;
}
mutex_lock(&ua_idr_mutex);
auth = idr_find(ua_idr, uid);
if (!auth) {
mutex_unlock(&ua_idr_mutex);
pr_err("[AUTH_CTRL] no auth data for this uid to switch=%d\n", uid);
return -UID_NOT_FOUND;
}
get_auth_struct(auth);
mutex_unlock(&ua_idr_mutex);
mutex_lock(&auth->mutex);
if (auth->status == AUTH_STATUS_DEAD) {
mutex_unlock(&auth->mutex);
put_auth_struct(auth);
return -INVALID_AUTH;
}
set_auth_flag(data, auth);
#ifdef CONFIG_QOS_CTRL
qos_switch(auth, status);
#endif
auth->status = status;
mutex_unlock(&auth->mutex);
put_auth_struct(auth);
return 0;
}
typedef int (*auth_manipulate_func)(struct auth_ctrl_data *data);
static auth_manipulate_func auth_func_array[AUTH_MAX_NR] = {
/*
* auth_enable: Start authority control for specific uid.
* auth_delte: End authroity control, remove statistic datas.
* auth_get: Get auth info, deprecated.
* auth_switch: Change authority flag and status for specific uid.
*/
NULL,
auth_enable,
auth_delete,
auth_get,
auth_switch,
};
static long do_auth_manipulate(struct auth_ctrl_data *data)
{
long ret = 0;
unsigned int type = data->type;
if (type >= AUTH_MAX_NR) {
pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION type not valid\n");
return -ARG_INVALID;
}
if (auth_func_array[type])
ret = (long)(*auth_func_array[type])(data);
return ret;
}
static long ctrl_auth_basic_operation(struct file *file, void __user *uarg)
{
struct auth_ctrl_data auth_data;
long ret;
if (copy_from_user(&auth_data, uarg, sizeof(struct auth_ctrl_data))) {
pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION copy data failed\n");
return -ARG_INVALID;
}
ret = do_auth_manipulate(&auth_data);
if (ret < 0) {
pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION failed\n");
return ret;
}
if (copy_to_user(uarg, &auth_data, sizeof(struct auth_ctrl_data))) {
pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION send data failed\n");
return -ARG_INVALID;
}
return 0;
}
long auth_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *uarg = (void __user *)arg;
unsigned int func_cmd = _IOC_NR(cmd);
if (uarg == NULL) {
pr_err("%s: invalid user uarg\n", __func__);
return -EINVAL;
}
if (_IOC_TYPE(cmd) != AUTH_CTRL_IPC_MAGIG) {
pr_err("%s: authority ctrl magic fail, TYPE=%d\n",
__func__, _IOC_TYPE(cmd));
return -EINVAL;
}
if (func_cmd >= AUTH_CTRL_MAX_NR) {
pr_err("%s: authority ctrl cmd error, cmd:%d\n",
__func__, _IOC_TYPE(cmd));
return -EINVAL;
}
if (g_func_array[func_cmd])
return (*g_func_array[func_cmd])(file, uarg);
return -EINVAL;
}
#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
* Return current's uid if p is NULL
*/
static inline unsigned int get_authority_uid(struct task_struct *p)
{
unsigned int uid = get_true_uid(p);
if (super_uid(uid))
uid = SUPER_UID;
return uid;
}
static unsigned int auth_flag(struct auth_struct *auth, unsigned int type)
{
switch (type) {
#ifdef CONFIG_RTG_AUTHORITY
case RTG_AUTH_FLAG:
return auth->rtg_auth_flag;
#endif
#ifdef CONFIG_QOS_AUTHORITY
case QOS_AUTH_FLAG:
return auth->qos_auth_flag;
#endif
default:
pr_err("[AUTH_CTRL] not valid auth type\n");
return INVALIED_AUTH_FLAG;
}
}
bool check_authorized(unsigned int func_id, unsigned int type)
{
bool authorized = false;
struct auth_struct *auth;
unsigned int af = get_authority_flag(func_id);
unsigned int uid = get_authority_uid(NULL);
mutex_lock(&ua_idr_mutex);
if (!ua_idr) {
mutex_unlock(&ua_idr_mutex);
pr_err("[AUTH_CTRL] authority idr table missed, auth failed\n");
return authorized;
}
auth = (struct auth_struct *)idr_find(ua_idr, uid);
if (!auth) {
mutex_unlock(&ua_idr_mutex);
pr_err("[AUTH_CTRL] no auth data for this uid=%d\n", uid);
return authorized;
}
get_auth_struct(auth);
mutex_unlock(&ua_idr_mutex);
mutex_lock(&auth->mutex);
if (auth->status == AUTH_STATUS_DEAD) {
mutex_unlock(&auth->mutex);
pr_info("[AUTH_CTRL] not valied auth for uid %d\n", uid);
put_auth_struct(auth);
return authorized;
}
if (auth && (auth_flag(auth, type) & af))
authorized = true;
mutex_unlock(&auth->mutex);
put_auth_struct(auth);
return authorized;
}
/*
* Return 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_auth_struct before the calling end
*/
struct auth_struct *get_authority(struct task_struct *p)
{
unsigned int uid = get_authority_uid(p);
struct auth_struct *auth;
mutex_lock(&ua_idr_mutex);
auth = idr_find(ua_idr, uid);
if (auth)
get_auth_struct(auth);
mutex_unlock(&ua_idr_mutex);
return auth;
}
static const struct file_operations auth_ctrl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = auth_ctrl_ioctl,
.compat_ioctl = auth_ctrl_ioctl,
};
static struct miscdevice auth_ctrl_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "auth_ctrl",
.fops = &auth_ctrl_fops,
};
static __init int auth_ctrl_init_module(void)
{
int err;
err = misc_register(&auth_ctrl_device);
if (err < 0) {
pr_err("auth_ctrl register failed\n");
return err;
}
pr_info("auth_ctrl init success\n");
BUG_ON(init_authority_control());
#ifdef CONFIG_QOS_CTRL
init_qos_ctrl();
#endif
init_sched_auth_debug_procfs();
return 0;
}
static void auth_ctrl_exit_module(void)
{
remove_authority_control();
misc_deregister(&auth_ctrl_device);
}
/* module entry points */
module_init(auth_ctrl_init_module);
module_exit(auth_ctrl_exit_module);
MODULE_LICENSE("GPL v2");
+52
View File
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* drivers/auth_ctl/auth_ctrl.h
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*
*/
#ifndef __AUTH_CTRL_H
#define __AUTH_CTRL_H
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/refcount.h>
#include <linux/sched/qos_ctrl.h>
struct auth_struct {
struct mutex mutex;
refcount_t usage;
unsigned int status;
#ifdef CONFIG_RTG_AUTHORITY
unsigned int rtg_auth_flag;
#endif
#ifdef CONFIG_QOS_AUTHORITY
unsigned int qos_auth_flag;
#endif
#ifdef CONFIG_QOS_CTRL
unsigned int num[NR_QOS];
struct list_head tasks[NR_QOS];
#endif
};
/*
* for debug fs
*/
struct idr *get_auth_ctrl_idr(void);
struct mutex *get_auth_idr_mutex(void);
#ifdef CONFIG_AUTH_QOS_DEBUG
int __init init_sched_auth_debug_procfs(void);
#else
static inline int init_sched_auth_debug_procfs(void)
{
return 0;
}
#endif
#endif /* __AUTH_CTRL_H */
+157
View File
@@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/auth_ctl/auth_qos_debug.c
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*
*/
#include <linux/cred.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/sched/auth_ctrl.h>
#include <linux/sched/rtg_auth.h>
#include <linux/sched/qos_ctrl.h>
#include <linux/sched/qos_auth.h>
#include "auth_ctrl.h"
#include "qos_ctrl.h"
#define seq_printf_auth(m, x...) \
do { \
if (m) \
seq_printf(m, x); \
else \
printk(x); \
} while (0)
static void print_auth_id(struct seq_file *file,
const int uid)
{
seq_printf_auth(file, "AUTH_ID :%d\n", uid);
}
static void print_auth_info(struct seq_file *file,
const struct auth_struct *auth)
{
seq_printf_auth(file, "AUTH_STATUS :%d\n", auth->status);
#ifdef CONFIG_RTG_AUTHORITY
seq_printf_auth(file, "RTG_FLAG :%04x\n", auth->rtg_auth_flag);
#endif
#ifdef CONFIG_QOS_AUTHORITY
seq_printf_auth(file, "QOS_FLAG :%04x\n", auth->qos_auth_flag);
#endif
}
static void print_qos_count(struct seq_file *file,
const struct auth_struct *auth)
{
int i;
for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i)
seq_printf_auth(file, "QOS level %d thread nr :%d\n", i, auth->num[i]);
}
static void print_qos_thread(struct seq_file *file,
const struct auth_struct *auth)
{
struct qos_task_struct *tmp, *next;
struct task_struct *p;
int i;
for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
seq_printf_auth(file, "QOS level %d threads:", i);
list_for_each_entry_safe(tmp, next, &auth->tasks[i], qos_list) {
p = container_of(tmp, struct task_struct, qts);
seq_printf_auth(file, "%d ", p->pid);
}
seq_printf_auth(file, "\n");
}
}
static inline void print_auth_struct(struct seq_file *file, struct auth_struct *auth)
{
print_auth_info(file, auth);
seq_printf_auth(file, "\n");
print_qos_count(file, auth);
seq_printf_auth(file, "\n");
#ifdef CONFIG_QOS_CTRL
print_qos_thread(file, auth);
#endif
seq_printf_auth(file, "---------------------------------------------------------\n");
}
int authority_printf_handler(int id, void *p, void *para)
{
struct auth_struct *auth = (struct auth_struct *)p;
struct seq_file *file = (struct seq_file *)para;
/*
* data consistency is not that important here
*/
seq_printf_auth(file, "\n\n");
print_auth_id(file, id);
seq_printf_auth(file, "\n");
/* no need to add refcount here, auth must alive in ua_idr_mutex */
print_auth_struct(file, auth);
return 0;
}
static int sched_auth_debug_show(struct seq_file *file, void *param)
{
struct idr *ua_idr = get_auth_ctrl_idr();
struct mutex *ua_idr_mutex = get_auth_idr_mutex();
/*
* NOTICE:
* if mutex in authority_printf_handler, sleep may occur
* change ths spin_lock to mutex, or remove mutex in handler
*/
mutex_lock(ua_idr_mutex);
/* will never return 0 here, auth in ua_idr must alive */
idr_for_each(ua_idr, authority_printf_handler, file);
mutex_unlock(ua_idr_mutex);
return 0;
}
static int sched_auth_debug_release(struct inode *inode, struct file *file)
{
seq_release(inode, file);
return 0;
}
static int sched_auth_debug_open(struct inode *inode, struct file *filp)
{
return single_open(filp, sched_auth_debug_show, NULL);
}
static const struct proc_ops sched_auth_debug_fops = {
.proc_open = sched_auth_debug_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = sched_auth_debug_release,
};
int __init init_sched_auth_debug_procfs(void)
{
struct proc_dir_entry *pe = NULL;
pe = proc_create("sched_auth_qos_debug",
0400, NULL, &sched_auth_debug_fops);
if (unlikely(!pe))
return -ENOMEM;
return 0;
}
+662
View File
@@ -0,0 +1,662 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/auth_ctl/auth_ctrl.c
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*
*/
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/stop_machine.h>
#include <linux/sched/auth_ctrl.h>
#include <linux/sched/rtg_auth.h>
#include <linux/sched/qos_ctrl.h>
#include <linux/sched/qos_auth.h>
#include <uapi/linux/sched/types.h>
#include "auth_ctrl.h"
#include "qos_ctrl.h"
typedef long (*qos_ctrl_func)(struct file *file, void __user *uarg);
static long ctrl_qos_operation(struct file *file, void __user *uarg);
static long ctrl_qos_policy(struct file *file, void __user *uarg);
static qos_ctrl_func g_func_array[QOS_CTRL_MAX_NR] = {
NULL, /* reserved */
ctrl_qos_operation,
ctrl_qos_policy,
};
static struct qos_policy_map qos_policy_array[QOS_POLICY_MAX_NR];
void remove_qos_tasks(struct auth_struct *auth)
{
int i;
struct qos_task_struct *tmp, *next;
struct task_struct *p;
mutex_lock(&auth->mutex);
for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
list_for_each_entry_safe(tmp, next, &auth->tasks[i], qos_list) {
p = container_of(tmp, struct task_struct, qts);
if (!list_empty(&tmp->qos_list)) {
list_del_init(&tmp->qos_list);
tmp->in_qos = NO_QOS;
put_task_struct(p);
}
}
}
mutex_unlock(&auth->mutex);
}
static void init_sched_attr(struct sched_attr *attr)
{
memset(attr, 0, sizeof(struct sched_attr));
}
static inline bool is_system(unsigned int uid)
{
return uid == SYSTEM_UID;
}
/* This function must be called when p is valid. That means the p's refcount must exist */
static int sched_set_task_qos_attr(struct task_struct *p, int level, int status)
{
struct qos_policy_item *item;
struct qos_policy_map *policy_map;
struct sched_attr attr;
read_lock(&qos_policy_array[status].lock);
if (!qos_policy_array[status].initialized) {
pr_err("[QOS_CTRL] dirty qos policy, pid=%d, uid=%d, status=%d\n",
p->pid, p->cred->uid.val, status);
read_unlock(&qos_policy_array[status].lock);
return -DIRTY_QOS_POLICY;
}
policy_map = &qos_policy_array[status];
item = &policy_map->levels[level];
init_sched_attr(&attr);
attr.size = sizeof(struct sched_attr);
attr.sched_policy = SCHED_NORMAL;
if (policy_map->policy_flag & QOS_FLAG_NICE)
attr.sched_nice = item->nice;
if (policy_map->policy_flag & QOS_FLAG_LATENCY_NICE) {
attr.sched_flags |= SCHED_FLAG_LATENCY_NICE;
attr.sched_latency_nice = item->latency_nice;
}
if ((policy_map->policy_flag & QOS_FLAG_RT) && item->rt_sched_priority) {
attr.sched_policy = SCHED_FIFO;
attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
attr.sched_priority = item->rt_sched_priority;
}
read_unlock(&qos_policy_array[status].lock);
if (unlikely(p->flags & PF_EXITING)) {
pr_info("[QOS_CTRL] dying task, no need to set qos\n");
return -THREAD_EXITING;
}
return sched_setattr_nocheck(p, &attr);
}
/*
* Switch qos mode when status changed.
* Lock auth before calling this function
*/
void qos_switch(struct auth_struct *auth, int target_status)
{
int i;
int ret;
struct task_struct *task;
struct qos_task_struct *qts;
if (!auth) {
pr_err("[QOS_CTRL] auth no exist, qos switch failed\n");
return;
}
lockdep_assert_held(&auth->mutex);
if (auth->status == target_status) {
pr_info("[QOS_CTRL] same status, no need to switch qos\n");
return;
}
for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
list_for_each_entry(qts, &auth->tasks[i], qos_list) {
task = container_of(qts, struct task_struct, qts);
ret = sched_set_task_qos_attr(task, i, target_status);
if (ret)
pr_err("[QOS_CTRL] set qos attr failed, qos switch failed\n");
}
}
}
static int qos_insert_task(struct task_struct *p, struct list_head *head, unsigned int level)
{
struct qos_task_struct *qts = &p->qts;
if (qts->in_qos > NO_QOS) {
pr_err("[QOS_CTRL] qos apply still active, no duplicate add\n");
return -PID_DUPLICATE;
}
if (likely(list_empty(&qts->qos_list))) {
get_task_struct(p);
list_add(&qts->qos_list, head);
qts->in_qos = level;
}
return 0;
}
static int qos_remove_task(struct task_struct *p)
{
struct qos_task_struct *qts = (struct qos_task_struct *) &p->qts;
if (qts->in_qos == NO_QOS) {
pr_err("[QOS_CTRL] task not in qos, no need to remove\n");
return -PID_NOT_EXIST;
}
if (likely(!list_empty(&qts->qos_list))) {
list_del_init(&qts->qos_list);
qts->in_qos = NO_QOS;
put_task_struct(p);
}
return 0;
}
static inline bool same_uid(struct task_struct *dude, struct task_struct *bro)
{
return uid_eq(task_uid(dude), task_uid(bro));
}
static inline bool super_user(struct task_struct *p)
{
return super_uid(task_uid(p).val);
}
/*
* judge permission for changing other tasks' qos
*/
static bool can_change_qos(struct task_struct *p)
{
if (p != current && !same_uid(current, p) && !super_user(current)) {
pr_err("[QOS_CTRL] %d apply for others not permit\n", p->pid);
return false;
}
return true;
}
int qos_apply(struct qos_ctrl_data *data)
{
unsigned int level = data->level;
struct auth_struct *auth;
struct task_struct *p;
struct qos_task_struct *qts;
int pid = data->pid;
int ret;
if (level >= NR_QOS || level == NO_QOS) {
pr_err("[QOS_CTRL] no this qos level, qos apply failed\n");
ret = -ARG_INVALID;
goto out;
}
p = find_get_task_by_vpid((pid_t)pid);
if (unlikely(!p)) {
pr_err("[QOS_CTRL] no matching task for this pid, qos apply failed\n");
ret = -ESRCH;
goto out;
}
if (unlikely(p->flags & PF_EXITING)) {
pr_info("[QOS_CTRL] dying task, no need to set qos\n");
ret = -THREAD_EXITING;
goto out_put_task;
}
if (!can_change_qos(p)) {
pr_err("[QOS_CTRL] apply for others not permit\n");
ret = -ARG_INVALID;
goto out_put_task;
}
auth = get_authority(p);
if (!auth) {
pr_err("[QOS_CTRL] no auth data for pid=%d(%s) this uid=%d, qos apply failed\n",
p->pid, p->comm, p->cred->uid.val);
put_task_struct(p);
ret = -UID_NOT_FOUND;
goto out;
}
mutex_lock(&auth->mutex);
if (auth->status == AUTH_STATUS_DEAD) {
pr_err("[QOS_CTRL] this auth data has been deleted\n");
ret = -INVALID_AUTH;
goto out_unlock;
}
if (auth->num[level] >= QOS_NUM_MAX) {
pr_err("[QOS_CTRL] qos num exceeds limit, cached only\n");
ret = -QOS_THREAD_NUM_EXCEED_LIMIT;
goto out_unlock;
}
qts = (struct qos_task_struct *) &p->qts;
/* effective qos must in range [NO_QOS, NR_QOS) */
if (qts->in_qos != NO_QOS) {
if (qts->in_qos == level) {
ret = 0;
goto out_unlock;
}
--auth->num[qts->in_qos];
qos_remove_task(p);
}
ret = qos_insert_task(p, &auth->tasks[level], level);
if (ret < 0) {
pr_err("[QOS_CTRL] insert task to qos list %d failed\n", level);
goto out_unlock;
}
++auth->num[level];
ret = sched_set_task_qos_attr(p, level, auth->status);
if (ret) {
pr_err("[QOS_CTRL] set qos_level %d for thread %d on status %d failed\n",
level, p->pid, auth->status);
--auth->num[level];
qos_remove_task(p);
}
out_unlock:
mutex_unlock(&auth->mutex);
put_auth_struct(auth);
out_put_task:
put_task_struct(p);
out:
return ret;
}
int qos_leave(struct qos_ctrl_data *data)
{
unsigned int level;
struct auth_struct *auth;
struct task_struct *p;
struct qos_task_struct *qts;
int pid = data->pid;
int ret;
p = find_get_task_by_vpid((pid_t)pid);
if (!p) {
pr_err("[QOS_CTRL] no matching task for this pid, qos apply failed\n");
ret = -ESRCH;
goto out;
}
if (unlikely(p->flags & PF_EXITING)) {
pr_info("[QOS_CTRL] dying task, no need to set qos\n");
ret = -THREAD_EXITING;
goto out_put_task;
}
if (!can_change_qos(p)) {
pr_err("[QOS_CTRL] apply for others not permit\n");
ret = -ARG_INVALID;
goto out_put_task;
}
auth = get_authority(p);
if (!auth) {
pr_err("[QOS_CTRL] no auth data for pid=%d(%s) this uid=%d, qos stop failed\n",
p->pid, p->comm, p->cred->uid.val);
put_task_struct(p);
ret = -UID_NOT_FOUND;
goto out;
}
mutex_lock(&auth->mutex);
qts = (struct qos_task_struct *) &p->qts;
level = qts->in_qos;
if (level == NO_QOS) {
pr_err("[QOS_CTRL] task not in qos list, qos stop failed\n");
ret = -ARG_INVALID;
goto out_unlock;
}
if (auth->status == AUTH_STATUS_DEAD) {
pr_err("[QOS_CTRL] this auth data has been deleted\n");
ret = -INVALID_AUTH;
goto out_unlock;
}
ret = qos_remove_task(p);
if (ret < 0) {
pr_err("[QOS_CTRL] remove task from qos list %d failed\n", level);
goto out_unlock;
}
--auth->num[level];
/*
* NO NEED to judge whether current status is AUTH_STATUS_DISABLE.
* In the auth destoring context, the removing of thread's sched attr was protected by
* auth->mutex, AUTH_STATUS_DISABLED will never appear here.
*
* The second param 3 means nothing, actually you can use any valid level here, cause the
* policy matching AUTH_STATUS_DISABLED has default parameters for all qos level, which can
* keep a powerful thread to behave like a ordinary thread.
*/
ret = sched_set_task_qos_attr(p, 3, AUTH_STATUS_DISABLED);
if (ret)
pr_err("[QOS_CTRL] set qos_level %d for thread %d on status %d to default failed\n",
level, p->pid, auth->status);
out_unlock:
mutex_unlock(&auth->mutex);
put_auth_struct(auth);
out_put_task:
put_task_struct(p);
out:
return ret;
}
void init_task_qos(struct task_struct *p)
{
struct qos_task_struct *qts = (struct qos_task_struct *) &p->qts;
INIT_LIST_HEAD(&qts->qos_list);
qts->in_qos = NO_QOS;
}
/*
* Remove statistic info in auth when task exit
*/
void sched_exit_qos_list(struct task_struct *p)
{
struct auth_struct *auth;
struct qos_task_struct *qts = (struct qos_task_struct *) &p->qts;
/*
* 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(qts->in_qos == NO_QOS))
return;
auth = get_authority(p);
if (!auth)
goto out;
mutex_lock(&auth->mutex);
if (qts->in_qos == NO_QOS) {
mutex_unlock(&auth->mutex);
goto out_put_auth;
}
--auth->num[qts->in_qos];
list_del_init(&qts->qos_list);
qts->in_qos = NO_QOS;
mutex_unlock(&auth->mutex);
out_put_auth:
put_auth_struct(auth);
out:
return;
}
typedef int (*qos_manipulate_func)(struct qos_ctrl_data *data);
static qos_manipulate_func qos_func_array[QOS_OPERATION_CMD_MAX_NR] = {
NULL,
qos_apply, //1
qos_leave,
};
static long do_qos_manipulate(struct qos_ctrl_data *data)
{
long ret = 0;
unsigned int type = data->type;
if (type <= 0 || type >= QOS_OPERATION_CMD_MAX_NR) {
pr_err("[QOS_CTRL] CMD_ID_QOS_MANIPULATE type not valid\n");
return -ARG_INVALID;
}
if (qos_func_array[type])
ret = (long)(*qos_func_array[type])(data);
return ret;
}
static long ctrl_qos_operation(struct file *file, void __user *uarg)
{
struct qos_ctrl_data qos_data;
if (copy_from_user(&qos_data, uarg, sizeof(struct qos_ctrl_data))) {
pr_err("[QOS_CTRL] CMD_ID_QOS_APPLY copy data failed\n");
return -ARG_INVALID;
}
/* transfer user space qos level to kernel space qos level */
qos_data.level -= QOS_LEVEL_INTERVAL;
return do_qos_manipulate(&qos_data);
}
#define MAX_LATENCY_NICE 19
#define MIN_LATENCY_NICE -20
static inline bool valid_nice(int nice)
{
return nice >= MIN_NICE && nice <= MAX_NICE;
}
static inline bool valid_latency_nice(int latency_nice)
{
return latency_nice >= MIN_LATENCY_NICE && latency_nice <= MAX_LATENCY_NICE;
}
static inline bool valid_uclamp(int uclamp_min, int uclamp_max)
{
if (uclamp_min > uclamp_max)
return false;
if (uclamp_max > SCHED_CAPACITY_SCALE)
return false;
return true;
}
static inline bool valid_rt(int sched_priority)
{
if (sched_priority > MAX_USER_RT_PRIO - 1 || sched_priority < 0)
return false;
return true;
}
static bool valid_qos_flag(unsigned int qos_flag)
{
if (qos_flag & ~QOS_FLAG_ALL)
return false;
return true;
}
static inline bool valid_qos_item(struct qos_policy_datas *datas)
{
int i;
int type = datas->policy_type;
struct qos_policy_data *data;
if (type <= 0 || type >= QOS_POLICY_MAX_NR) {
pr_err("[QOS_CTRL] not valid qos policy type, policy change failed\n");
goto out_failed;
}
if (!valid_qos_flag(datas->policy_flag)) {
pr_err("[QOS_CTRL] not valid qos flag, policy change failed\n");
goto out_failed;
}
/* check user space qos polcicy data, level 0 reserved */
for (i = 0; i <= NR_QOS; ++i) {
data = &datas->policys[i];
if (!valid_nice(data->nice)) {
pr_err("[QOS_CTRL] invalid nice, policy change failed\n");
goto out_failed;
}
if (!valid_latency_nice(data->latency_nice)) {
pr_err("[QOS_CTRL] invalid latency_nice, policy change failed\n");
goto out_failed;
}
if (!valid_uclamp(data->uclamp_min, data->uclamp_max)) {
pr_err("[QOS_CTRL] invalid uclamp, policy change failed\n");
goto out_failed;
}
if (!valid_rt(data->rt_sched_priority)) {
pr_err("[QOS_CTRL] invalid rt, policy change failed\n");
goto out_failed;
}
}
return true;
out_failed:
pr_err("[QOS_CTRL] not valid qos policy params\n");
return false;
}
static long do_qos_policy_change(struct qos_policy_datas *datas)
{
long ret = 0;
int i;
struct qos_policy_item *item;
struct qos_policy_data *data;
int type = datas->policy_type;
if (type >= QOS_POLICY_MAX_NR) {
pr_err("[QOS_CTRL] not valid policy type\n");
goto out_failed;
}
if (!valid_qos_item(datas))
goto out_failed;
write_lock(&qos_policy_array[type].lock);
for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
item = &qos_policy_array[type].levels[i];
/* user space policy params */
data = &datas->policys[i + QOS_LEVEL_INTERVAL];
item->nice = data->nice;
item->latency_nice = data->latency_nice;
item->uclamp_min = data->uclamp_min;
item->uclamp_max = data->uclamp_max;
/* only specific qos level could use SCHED_FIFO */
item->rt_sched_priority = (i < MIN_RT_QOS_LEVEL) ? 0 :
data->rt_sched_priority;
}
qos_policy_array[type].policy_flag = datas->policy_flag;
qos_policy_array[type].initialized = true;
write_unlock(&qos_policy_array[type].lock);
return ret;
out_failed:
return -ARG_INVALID;
}
static long ctrl_qos_policy(struct file *file, void __user *uarg)
{
struct qos_policy_datas policy_datas;
if (copy_from_user(&policy_datas, uarg, sizeof(struct qos_policy_datas))) {
pr_err("[QOS_CTRL] CMD_ID_QOS_APPLY copy data failed\n");
return -ARG_INVALID;
}
return do_qos_policy_change(&policy_datas);
}
long do_qos_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *uarg = (void __user *)arg;
unsigned int func_cmd = _IOC_NR(cmd);
if (uarg == NULL) {
pr_err("%s: invalid user uarg\n", __func__);
return -EINVAL;
}
if (_IOC_TYPE(cmd) != QOS_CTRL_IPC_MAGIG) {
pr_err("%s: qos ctrl magic fail, TYPE=%d\n",
__func__, _IOC_TYPE(cmd));
return -EINVAL;
}
if (func_cmd >= QOS_CTRL_MAX_NR) {
pr_err("%s: qos ctrl cmd error, cmd:%d\n",
__func__, _IOC_TYPE(cmd));
return -EINVAL;
}
#ifdef CONFIG_QOS_AUTHORITY
if (!check_authorized(func_cmd, QOS_AUTH_FLAG)) {
pr_err("[QOS_CTRL] %s: uid not authorized\n", __func__);
return -UID_NOT_AUTHORIZED;
}
#endif
if (g_func_array[func_cmd])
return (*g_func_array[func_cmd])(file, uarg);
return -EINVAL;
}
static void init_qos_policy_array(void)
{
int i;
/* index 0 reserved */
for (i = 1; i < QOS_POLICY_MAX_NR; ++i)
rwlock_init(&qos_policy_array[i].lock);
pr_info("[QOS_CTRL] lock in qos policy initialized\n");
}
int __init init_qos_ctrl(void)
{
init_qos_policy_array();
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* drivers/auth_ctl/qos_ctrl.h
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*
*/
#ifndef __QOS_CTRL_H
#define __QOS_CTRL_H
#include "../../kernel/sched/sched.h"
#include <linux/sched/qos_ctrl.h>
/* qos level interval between user space and kernel space */
#define QOS_LEVEL_INTERVAL 1
/* min qos level used in kernel space, begin index for LOOP */
#define QOS_POLICY_MIN_LEVEL (NO_QOS + QOS_LEVEL_INTERVAL)
struct qos_policy_item {
int nice;
int latency_nice;
int uclamp_min;
int uclamp_max;
int rt_sched_priority;
};
struct qos_policy_map {
rwlock_t lock;
bool initialized;
unsigned int policy_flag;
struct qos_policy_item levels[NR_QOS];
};
int __init init_qos_ctrl(void);
#endif /* __OQS_CTRL_H */
Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

+116
View File
@@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/sched/auth_ctrl.h
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*/
#ifndef _AUTH_CTRL_H
#define _AUTH_CTRL_H
#include <linux/fs.h>
#define ROOT_UID 0
#define SYSTEM_UID 1000
#define SUPER_UID SYSTEM_UID
#define super_uid(uid) (uid == ROOT_UID || uid == SYSTEM_UID)
enum auth_ctrl_cmdid {
BASIC_AUTH_CTRL = 1,
AUTH_CTRL_MAX_NR
};
#define AUTH_CTRL_IPC_MAGIG 0xCD
#define BASIC_AUTH_CTRL_OPERATION \
_IOWR(AUTH_CTRL_IPC_MAGIG, BASIC_AUTH_CTRL, struct auth_ctrl_data)
enum auth_flag_type {
#ifdef CONFIG_RTG_AUTHORITY
RTG_AUTH_FLAG,
#endif
#ifdef CONFIG_QOS_AUTHORITY
QOS_AUTH_FLAG,
#endif
};
#define INVALIED_AUTH_FLAG 0x00000000
struct auth_ctrl_data {
unsigned int uid;
/*
* type: operation type, see auth_manipulate_type, valid range [1, AUTH_MAX_NR)
*
* rtg_ua_flag: authority flag for RTG, see AF_RTG_ALL
*
* qos_ua_flag: authority flag for QOS, see AF_QOS_ALL
*
* status: current status for uid, use to match qos policy, see auth_status and
* qos_policy_type, valid range [1, AUTH_STATUS_MAX_NR - 1)
*
*/
unsigned int type;
unsigned int rtg_ua_flag;
unsigned int qos_ua_flag;
unsigned int status;
};
enum auth_err_no {
ARG_INVALID = 1,
THREAD_EXITING,
DIRTY_QOS_POLICY,
UID_NOT_AUTHORIZED,
UID_NOT_FOUND,
PID_DUPLICATE,
PID_NOT_EXIST,
INVALID_AUTH,
QOS_THREAD_NUM_EXCEED_LIMIT,
};
enum auth_manipulate_type {
AUTH_ENABLE = 1,
AUTH_DELETE,
AUTH_GET,
AUTH_SWITCH,
AUTH_MAX_NR,
};
#ifndef CONFIG_QOS_POLICY_MAX_NR
#define QOS_STATUS_COUNT 5
#else
#define QOS_STATUS_COUNT CONFIG_QOS_POLICY_MAX_NR
#endif
/* keep match with qos_policy_type */
enum auth_status {
/* reserved fo QOS_POLICY_DEFAULT, no qos supply in this status */
AUTH_STATUS_DISABLED = 1,
/* reserved for ROOT and SYSTEM */
AUTH_STATUS_SYSTEM_SERVER = 2,
/*
* these space for user specific status
* range (AUTH_STATUS_SYSTEM_SERVER, AUTH_STATUS_DEAD)
*
* initial the policy in matching index of qos_policy_array first before use
* see ctrl_qos_policy
*/
/* reserved for destorying auth_struct*/
AUTH_STATUS_DEAD = QOS_STATUS_COUNT,
AUTH_STATUS_MAX_NR = QOS_STATUS_COUNT + 1,
};
struct auth_struct;
long auth_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
void get_auth_struct(struct auth_struct *auth);
void put_auth_struct(struct auth_struct *auth);
struct auth_struct *get_authority(struct task_struct *p);
bool check_authorized(unsigned int func_id, unsigned int type);
#endif /* _AUTH_CTRL_H */
+33
View File
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/sched/qos_auth.h
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*/
#ifndef _QOS_AUTH_H
#define _QOS_AUTH_H
#include <linux/sched.h>
#include <linux/sched/auth_ctrl.h>
/*
* QOS authority flags for SYSTEM or ROOT
*
* keep sync with qos_ctrl_cmdid
* when add a new cmd to qos_ctrl_cmdid
* keep new_flag = (old_flag << 1) + 1
* up to now, next flag value is 0x0007
*/
#define AF_QOS_ALL 0x0003
/*
* delegated authority for normal uid
* trim access range for QOS
*/
#define AF_QOS_DELEGATED 0x0001
bool check_authorized(unsigned int func_id, unsigned int type);
#endif /* _QOS_AUTH_H */
+119
View File
@@ -0,0 +1,119 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/sched/qos_ctrl.h
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*/
#ifndef _QOS_CTRL_H
#define _QOS_CTRL_H
#include <linux/sched.h>
#include <linux/fs.h>
enum qos_ctrl_cmdid {
QOS_CTRL = 1,
QOS_POLICY,
QOS_CTRL_MAX_NR
};
#define QOS_CTRL_IPC_MAGIG 0xCC
#define QOS_CTRL_BASIC_OPERATION \
_IOWR(QOS_CTRL_IPC_MAGIG, QOS_CTRL, struct qos_ctrl_data)
#define QOS_CTRL_POLICY_OPERATION \
_IOWR(QOS_CTRL_IPC_MAGIG, QOS_POLICY, struct qos_policy_datas)
#define NO_QOS -1
#define NR_QOS 6
#define NR_RT_QOS 1
#define MIN_RT_QOS_LEVEL (NR_QOS - NR_RT_QOS)
#define QOS_NUM_MAX 2000
enum qos_manipulate_type {
QOS_APPLY = 1,
QOS_LEAVE,
QOS_OPERATION_CMD_MAX_NR,
};
#ifndef CONFIG_QOS_POLICY_MAX_NR
#define QOS_POLICYS_COUNT 5
#else
#define QOS_POLICYS_COUNT CONFIG_QOS_POLICY_MAX_NR
#endif
/*
* keep match with auth_status
*
* range (QOS_POLICY_SYSTEM, QOS_POLICY_MAX_NR) could defined by user
* use ctrl_qos_policy
*/
enum qos_policy_type {
QOS_POLICY_DEFAULT = 1, /* reserved for "NO QOS" */
QOS_POLICY_SYSTEM = 2, /* reserved for ROOT and SYSTEM */
QOS_POLICY_MAX_NR = QOS_POLICYS_COUNT,
};
struct qos_ctrl_data {
int pid;
/*
* type: operation type, see qos_manipulate_type
* level: valid from 1 to NR_QOS. Larger value, more aggressive supply
*/
unsigned int type;
/*
* user space level, range from [1, NR_QOS]
*
* NOTICE!!!:
* minus 1 before use in kernel, so the kernel range is [0, NR_QOS)
*/
unsigned int level;
};
struct qos_policy_data {
int nice;
int latency_nice;
int uclamp_min;
int uclamp_max;
int rt_sched_priority;
};
#define QOS_FLAG_NICE 0x01
#define QOS_FLAG_LATENCY_NICE 0x02
#define QOS_FLAG_UCLAMP 0x04
#define QOS_FLAG_RT 0x08
#define QOS_FLAG_ALL (QOS_FLAG_NICE | \
QOS_FLAG_LATENCY_NICE | \
QOS_FLAG_UCLAMP | \
QOS_FLAG_RT)
struct qos_policy_datas {
/*
* policy_type: id for qos policy, valid from [1, QOS_POLICY_MAX_NR)
* policy_flag: control valid sched attr for policy, QOS_FLAG_ALL for whole access
* policys: sched params for specific level qos, minus 1 for matching struct in kerenl
*/
int policy_type;
unsigned int policy_flag;
struct qos_policy_data policys[NR_QOS + 1];
};
struct auth_struct;
int qos_apply(struct qos_ctrl_data *data);
int qos_leave(struct qos_ctrl_data *data);
void qos_switch(struct auth_struct *auth, int target_status);
void init_task_qos(struct task_struct *p);
void sched_exit_qos_list(struct task_struct *p);
void remove_qos_tasks(struct auth_struct *auth);
long do_qos_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#endif /* _QOS_CTRL_H */
+33
View File
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/sched/rtg_auth.h
*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*/
#ifndef _RTG_AUTH_H
#define _RTG_AUTH_H
#include <linux/sched.h>
#include <linux/sched/auth_ctrl.h>
/*
* 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 0x3fff
*/
#define AF_RTG_ALL 0x1fff
/*
* delegated authority for normal uid
* trim access range for RTG
*/
#define AF_RTG_DELEGATED 0x1fff
bool check_authorized(unsigned int func_id, unsigned int type);
#endif /* _RTG_AUTH_H */