hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9GZAQ CVE: NA
--------------------------------
Introduce ioctl interfaces to get relationship for task, which facilitating the acquisition and use of relationship in user mode.
Signed-off-by: Hui Tang tanghui20@huawei.com --- include/linux/sched/relationship.h | 7 ++ include/uapi/linux/sched_ctrl.h | 57 ++++++++++++ kernel/sched/Makefile | 2 +- kernel/sched/fair.c | 49 ++++++++++ kernel/sched/relationship.c | 31 +++++++ kernel/sched/relationship_ioctl.c | 142 +++++++++++++++++++++++++++++ 6 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 include/uapi/linux/sched_ctrl.h create mode 100644 kernel/sched/relationship_ioctl.c
diff --git a/include/linux/sched/relationship.h b/include/linux/sched/relationship.h index f603ed71e3e4..45861f66ac4e 100644 --- a/include/linux/sched/relationship.h +++ b/include/linux/sched/relationship.h @@ -5,6 +5,7 @@ #include <linux/nodemask.h> #include <linux/jump_label.h> #include <linux/refcount.h> +#include <uapi/linux/sched_ctrl.h>
#define FAULT_NODES_MAX 4
@@ -127,6 +128,12 @@ extern void sched_relationship_free(struct task_struct *p); void task_relationship_free(struct task_struct *tsk, bool reset); extern bool task_relationship_supported(struct task_struct *tsk); extern int sched_net_relationship_submit(struct net_relationship_req *req); +extern void +sctl_sched_get_net_relationship(struct task_struct *tsk, + struct sctl_net_relationship_info *info); +extern void +sctl_sched_get_mem_relationship(struct task_struct *tsk, + struct sctl_mem_relationship_info *info); extern void sched_get_mm_relationship(struct task_struct *tsk, struct bpf_relationship_get_args *args); extern void sched_get_relationship(struct task_struct *tsk, diff --git a/include/uapi/linux/sched_ctrl.h b/include/uapi/linux/sched_ctrl.h new file mode 100644 index 000000000000..13a4eb182d5e --- /dev/null +++ b/include/uapi/linux/sched_ctrl.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_SCHED_CTRL_H +#define _LINUX_SCHED_CTRL_H + +#include <linux/types.h> + + +#define SCTL_IOC_MAGIC 'X' + +/* get task relationship */ +#define SCTL_GET_RSHIP \ + _IOR(SCTL_IOC_MAGIC, 0, struct sctl_get_relationship_args) + +#define SCTL_IOC_MAXNR 1 + +#define SCTL_MAX_NUMNODES 16 +#define SCTL_STR_MAX 64 +#define NR_TASK_FAULTS_TYPE 2 + +#define NO_RSHIP (-1) + +struct grp_hdr { + int gid; + char preferred_nid[SCTL_STR_MAX]; + int nr_tasks; +}; + +struct sctl_net_relationship_info { + int valid; + struct grp_hdr grp_hdr; + int nic_nid; + int rx_dev_idx; + int rx_dev_queue_idx; + unsigned long rx_dev_netns_cookie; + unsigned long rxtx_remote_bytes; + unsigned long rxtx_bytes; + unsigned long grp_rxtx_bytes; +}; + +struct sctl_mem_relationship_info { + int valid; + struct grp_hdr grp_hdr; + int nodes_num; + unsigned long total_faults; + unsigned long grp_total_faults; + unsigned long faults[SCTL_MAX_NUMNODES][NR_TASK_FAULTS_TYPE]; + unsigned long faults_cpu[SCTL_MAX_NUMNODES][NR_TASK_FAULTS_TYPE]; + unsigned long grp_faults[SCTL_MAX_NUMNODES][NR_TASK_FAULTS_TYPE]; + unsigned long grp_faults_cpu[SCTL_MAX_NUMNODES][NR_TASK_FAULTS_TYPE]; +}; + +struct sctl_get_relationship_args { + int tid; + struct sctl_net_relationship_info nrsi; + struct sctl_mem_relationship_info mrsi; +}; +#endif /* _LINUX_SCHED_CTRL_H */ diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile index 114dc36320c6..879c22e63c6c 100644 --- a/kernel/sched/Makefile +++ b/kernel/sched/Makefile @@ -40,4 +40,4 @@ obj-$(CONFIG_SCHED_CORE) += core_sched.o obj-$(CONFIG_BPF_SCHED) += bpf_sched.o obj-$(CONFIG_BPF_SCHED) += bpf_topology.o obj-$(CONFIG_QOS_SCHED_SMART_GRID) += grid/ -obj-$(CONFIG_SCHED_TASK_RELATIONSHIP) += relationship.o +obj-$(CONFIG_SCHED_TASK_RELATIONSHIP) += relationship.o relationship_ioctl.o diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5ec1acb809ed..92174e0f9bbe 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3043,6 +3043,55 @@ static inline void update_scan_period(struct task_struct *p, int new_cpu) #endif /* CONFIG_NUMA_BALANCING */
#ifdef CONFIG_SCHED_TASK_RELATIONSHIP +void sctl_sched_get_mem_relationship(struct task_struct *tsk, + struct sctl_mem_relationship_info *info) +{ +#ifdef CONFIG_NUMA_BALANCING + struct task_relationship *rship = tsk->rship; + int nid, priv, cpu_idx, mem_idx; + struct numa_group *grp; + + info->valid = false; + if (unlikely(!rship) || !tsk->numa_faults) + return; + + memset(info, 0, sizeof(*info)); + info->valid = true; + info->nodes_num = nr_node_ids; + info->grp_hdr.gid = NO_RSHIP; + info->total_faults = tsk->total_numa_faults; + + rcu_read_lock(); + + grp = rcu_dereference(tsk->numa_group); + if (grp) { + info->grp_hdr.gid = grp->gid; + info->grp_hdr.nr_tasks = grp->nr_tasks; + snprintf(info->grp_hdr.preferred_nid, SCTL_STR_MAX, "%*pbl", + nodemask_pr_args(&grp->preferred_nid)); + } + + for_each_online_node(nid) { + if (nid >= SCTL_MAX_NUMNODES) + break; + + for (priv = 0; priv < NR_NUMA_HINT_FAULT_TYPES; priv++) { + cpu_idx = task_faults_idx(NUMA_CPU, nid, priv); + mem_idx = task_faults_idx(NUMA_MEM, nid, priv); + info->faults[nid][priv] = tsk->numa_faults[mem_idx]; + info->faults_cpu[nid][priv] = tsk->numa_faults[cpu_idx]; + + if (grp) { + info->grp_faults[nid][priv] = grp->faults[mem_idx]; + info->grp_faults_cpu[nid][priv] = grp->faults_cpu[mem_idx]; + info->grp_total_faults = grp->total_faults; + } + } + } + + rcu_read_unlock(); +#endif +}
#ifdef CONFIG_BPF_SCHED void sched_get_mm_relationship(struct task_struct *tsk, diff --git a/kernel/sched/relationship.c b/kernel/sched/relationship.c index 89feb4b218d4..a85f85794f6e 100644 --- a/kernel/sched/relationship.c +++ b/kernel/sched/relationship.c @@ -366,6 +366,37 @@ void sched_get_relationship(struct task_struct *tsk, rcu_read_unlock(); }
+void sctl_sched_get_net_relationship(struct task_struct *tsk, + struct sctl_net_relationship_info *info) +{ + struct task_relationship *rship = tsk->rship; + struct net_group *grp; + + memset(info, 0, sizeof(*info)); + info->valid = true; + info->nic_nid = rship->nic_nid; + info->rx_dev_idx = rship->rx_dev_idx; + info->rx_dev_queue_idx = rship->rx_dev_queue_idx; + info->rx_dev_netns_cookie = rship->rx_dev_netns_cookie; + info->rxtx_remote_bytes = rship->rxtx_remote_bytes; + info->rxtx_bytes = rship->rxtx_bytes; + + info->grp_hdr.gid = NO_RSHIP; + + rcu_read_lock(); + + grp = rcu_dereference(rship->net_group); + if (grp) { + info->grp_hdr.gid = grp->hdr.gid; + info->grp_hdr.nr_tasks = grp->hdr.nr_tasks; + snprintf(info->grp_hdr.preferred_nid, SCTL_STR_MAX, "%*pbl", + nodemask_pr_args(&grp->hdr.preferred_nid)); + info->grp_rxtx_bytes = grp->rxtx_bytes; + } + + rcu_read_unlock(); +} + void task_relationship_free(struct task_struct *tsk, bool reset) { if (!task_relationship_used()) diff --git a/kernel/sched/relationship_ioctl.c b/kernel/sched/relationship_ioctl.c new file mode 100644 index 000000000000..229786961ec8 --- /dev/null +++ b/kernel/sched/relationship_ioctl.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Common code for support ioctl for schedluler + * + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd + * + * Author: Hui Tang tanghui20@huawei.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include <linux/string.h> +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <linux/fs.h> +#include <linux/compat.h> + +#include "sched.h" + +static int sched_ctl_open(struct inode *inode, struct file *filp) +{ + filp->private_data = NULL; + + return 0; +} + +static int sched_ctl_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int sched_ctrl_get_relationship(void __user *arg) +{ + struct sctl_get_relationship_args data; + struct task_struct *tsk; + pid_t pid; + + if (!task_relationship_used()) { + pr_err("task relationship disabled!\n"); + return -EPERM; + } + + if (copy_from_user(&data, arg, sizeof(data))) { + pr_err("fail to copy_from_user!\n"); + return -EFAULT; + } + + pid = data.tid; + + rcu_read_lock(); + + tsk = find_task_by_vpid(pid); + if (!tsk) { + rcu_read_unlock(); + return -ESRCH; + } + + if (!task_relationship_supported(tsk)) { + rcu_read_unlock(); + return -EPERM; + } + + sctl_sched_get_net_relationship(tsk, &data.nrsi); + sctl_sched_get_mem_relationship(tsk, &data.mrsi); + + rcu_read_unlock(); + + if (copy_to_user(arg, &data, sizeof(data))) { + pr_err("fail to copy_to_user!\n"); + return -EFAULT; + } + + return 0; +} + +static long sched_ctl_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + struct sched_ctl_data *data; + + if (_IOC_TYPE(cmd) != SCTL_IOC_MAGIC) + return -ENOTTY; + + if (_IOC_NR(cmd) > SCTL_IOC_MAXNR) + return -ENOTTY; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + data = filp->private_data; + + switch (cmd) { + case SCTL_GET_RSHIP: + ret = sched_ctrl_get_relationship((void __user *)(uintptr_t)arg); + break; + default: + ret = -EINVAL; + + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long +sched_ctl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + arg = (unsigned long)(uintptr_t)compat_ptr(arg); + return sched_ctl_ioctl(file, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + +static const struct file_operations sched_ctl_fops = { + .open = sched_ctl_open, + .release = sched_ctl_release, + .llseek = no_llseek, + .unlocked_ioctl = sched_ctl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sched_ctl_compat_ioctl, +#endif +}; + +static struct miscdevice sched_ctl_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "relationship_ctrl", + .fops = &sched_ctl_fops, +}; + +static int __init sched_ctl_device_init(void) +{ + return misc_register(&sched_ctl_device); +}; + +device_initcall(sched_ctl_device_init);