
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/release-management/issues/IC9Q31 -------------------------------- Refactor the xcall_enable logic to ensure only one reserved kabi in task_struct is used by xcall, which facilitates future xcall expansion. By the way, refactor the proc code by move to proc_xcall.c and replace fast_syscall_enabled() with system_supports_xcall(). Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- arch/arm64/include/asm/cpufeature.h | 6 ++ arch/arm64/include/asm/xcall.h | 15 ++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/asm-offsets.c | 2 +- arch/arm64/kernel/cpufeature.c | 5 -- arch/arm64/kernel/entry.S | 2 +- arch/arm64/kernel/xcall.c | 34 ++++++++ fs/proc/Makefile | 1 + fs/proc/base.c | 109 -------------------------- fs/proc/internal.h | 4 + fs/proc/proc_xcall.c | 115 ++++++++++++++++++++++++++++ include/linux/sched.h | 2 +- kernel/fork.c | 15 ++-- 13 files changed, 186 insertions(+), 125 deletions(-) create mode 100644 arch/arm64/include/asm/xcall.h create mode 100644 arch/arm64/kernel/xcall.c create mode 100644 fs/proc/proc_xcall.c diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index ebddd139f5ef..dd7d18cfbd1e 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -799,6 +799,12 @@ static __always_inline bool system_supports_xint(void) cpus_have_const_cap(ARM64_HAS_XINT); } +static __always_inline bool system_supports_xcall(void) +{ + return IS_ENABLED(CONFIG_FAST_SYSCALL) && + cpus_have_const_cap(ARM64_HAS_XCALL); +} + #ifdef CONFIG_ARM64_PBHA extern bool pbha_enabled; diff --git a/arch/arm64/include/asm/xcall.h b/arch/arm64/include/asm/xcall.h new file mode 100644 index 000000000000..d7e405ac3b13 --- /dev/null +++ b/arch/arm64/include/asm/xcall.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_XCALL_H +#define _LINUX_XCALL_H + +#include <linux/types.h> +#include <linux/sched.h> + +struct xcall_info { + /* Must be first! */ + DECLARE_BITMAP(xcall_enable, __NR_syscalls); +}; + +int xcall_init_task(struct task_struct *p, struct task_struct *orig); +void xcall_task_free(struct task_struct *p); +#endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 5b9951b6fb05..9db801f8fd22 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_CVM_GUEST) += cvm_guest.o cvm_tsi.o obj-y += vdso/ probes/ obj-$(CONFIG_COMPAT_VDSO) += vdso32/ obj-$(CONFIG_ARM64_ILP32) += vdso-ilp32/ +obj-$(CONFIG_FAST_SYSCALL) += xcall.o head-y := head.o extra-y += $(head-y) vmlinux.lds diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 7c6ad4b1667b..54a21afd4181 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -27,7 +27,7 @@ int main(void) { #ifdef CONFIG_FAST_SYSCALL - DEFINE(TSK_XCALL, offsetof(struct task_struct, xcall_enable)); + DEFINE(TSK_XCALL, offsetof(struct task_struct, xinfo)); #endif DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); BLANK(); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 85289b1db7bc..a1e2791bf0b9 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2164,11 +2164,6 @@ static int __init xcall_setup(char *str) } __setup("xcall", xcall_setup); -bool fast_syscall_enabled(void) -{ - return is_xcall_support; -} - static bool has_xcall_support(const struct arm64_cpu_capabilities *entry, int __unused) { return is_xcall_support; diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 4b340be57d66..976f629c60fe 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -707,7 +707,7 @@ SYM_CODE_END(el1_irq) .endm .macro check_xcall_enable - /* x21 = task_struct->xcall_enable */ + /* x21 = task_struct->xinfo->xcall_enable */ ldr_this_cpu x20, __entry_task, x21 ldr x21, [x20, #TSK_XCALL] /* x20 = sc_no / 8 */ diff --git a/arch/arm64/kernel/xcall.c b/arch/arm64/kernel/xcall.c new file mode 100644 index 000000000000..9dca8729b9da --- /dev/null +++ b/arch/arm64/kernel/xcall.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * xcall related code + * + * Copyright (C) 2025 Huawei Ltd. + */ + +#include <linux/bitmap.h> +#include <linux/slab.h> +#include <asm/xcall.h> + +int xcall_init_task(struct task_struct *p, struct task_struct *orig) +{ + if (likely(!system_supports_xcall())) + return 0; + + p->xinfo = kzalloc(sizeof(struct xcall_info), GFP_KERNEL); + if (!p->xinfo) + return -ENOMEM; + + if (orig->xinfo) + bitmap_copy(p->xinfo->xcall_enable, orig->xinfo->xcall_enable, + __NR_syscalls); + + return 0; +} + +void xcall_task_free(struct task_struct *p) +{ + if (likely(!system_supports_xcall())) + return; + + kfree(p->xinfo); +} diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 8704d41dd67c..d6a660ad167e 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -36,3 +36,4 @@ proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o proc-$(CONFIG_BOOT_CONFIG) += bootconfig.o obj-$(CONFIG_ETMEM_SCAN) += etmem_scan.o obj-$(CONFIG_ETMEM_SWAP) += etmem_swap.o +obj-$(CONFIG_FAST_SYSCALL) += proc_xcall.o diff --git a/fs/proc/base.c b/fs/proc/base.c index 3206960c4bd7..175c919e9f15 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3589,115 +3589,6 @@ static const struct file_operations proc_pid_sg_level_operations = { }; #endif -#ifdef CONFIG_FAST_SYSCALL -bool fast_syscall_enabled(void); - -static int xcall_show(struct seq_file *m, void *v) -{ - struct inode *inode = m->private; - struct task_struct *p; - unsigned int rs, re; - - if (!fast_syscall_enabled()) - return -EACCES; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - - if (!p->xcall_enable) - goto out; - - seq_printf(m, "Enabled Total[%d/%d]:", bitmap_weight(p->xcall_enable, __NR_syscalls), - __NR_syscalls); - - for (rs = 0, bitmap_next_set_region(p->xcall_enable, &rs, &re, __NR_syscalls); - rs < re; rs = re + 1, - bitmap_next_set_region(p->xcall_enable, &rs, &re, __NR_syscalls)) { - rs == (re - 1) ? seq_printf(m, "%d,", rs) : - seq_printf(m, "%d-%d,", rs, re - 1); - } - seq_puts(m, "\n"); -out: - put_task_struct(p); - - return 0; -} - -static int xcall_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, xcall_show, inode); -} - -static int xcall_enable_one(struct task_struct *p, unsigned int sc_no) -{ - bitmap_set(p->xcall_enable, sc_no, 1); - return 0; -} - -static int xcall_disable_one(struct task_struct *p, unsigned int sc_no) -{ - bitmap_clear(p->xcall_enable, sc_no, 1); - return 0; -} - -static ssize_t xcall_write(struct file *file, const char __user *buf, - size_t count, loff_t *offset) -{ - struct inode *inode = file_inode(file); - struct task_struct *p; - char buffer[TASK_COMM_LEN]; - const size_t maxlen = sizeof(buffer) - 1; - unsigned int sc_no = __NR_syscalls; - int ret = 0; - int is_clear = 0; - - if (!fast_syscall_enabled()) - return -EACCES; - - memset(buffer, 0, sizeof(buffer)); - if (!count || copy_from_user(buffer, buf, count > maxlen ? maxlen : count)) - return -EFAULT; - - p = get_proc_task(inode); - if (!p || !p->xcall_enable) - return -ESRCH; - - if (buffer[0] == '!') - is_clear = 1; - - if (kstrtouint(buffer + is_clear, 10, &sc_no)) { - ret = -EINVAL; - goto out; - } - - if (sc_no >= __NR_syscalls) { - ret = -EINVAL; - goto out; - } - - if (!is_clear && !test_bit(sc_no, p->xcall_enable)) - ret = xcall_enable_one(p, sc_no); - else if (is_clear && test_bit(sc_no, p->xcall_enable)) - ret = xcall_disable_one(p, sc_no); - else - ret = -EINVAL; - -out: - put_task_struct(p); - - return ret ? ret : count; -} - -static const struct file_operations proc_pid_xcall_operations = { - .open = xcall_open, - .read = seq_read, - .write = xcall_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - /* * Thread groups */ diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 104945bbeb9f..784f38611640 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -321,3 +321,7 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde) /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ pde->proc_dops = &proc_net_dentry_ops; } + +#ifdef CONFIG_FAST_SYSCALL +extern const struct file_operations proc_pid_xcall_operations; +#endif diff --git a/fs/proc/proc_xcall.c b/fs/proc/proc_xcall.c new file mode 100644 index 000000000000..b30dd698e057 --- /dev/null +++ b/fs/proc/proc_xcall.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/cpufeature.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <asm/xcall.h> +#include "internal.h" + +static int xcall_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + unsigned int rs, re; + struct xcall_info *xinfo; + + if (!system_supports_xcall()) + return -EACCES; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + xinfo = p->xinfo; + if (!xinfo) + goto out; + + seq_printf(m, "Enabled Total[%d/%d]:", bitmap_weight(xinfo->xcall_enable, __NR_syscalls), + __NR_syscalls); + + for (rs = 0, bitmap_next_set_region(xinfo->xcall_enable, &rs, &re, __NR_syscalls); + rs < re; rs = re + 1, + bitmap_next_set_region(xinfo->xcall_enable, &rs, &re, __NR_syscalls)) { + rs == (re - 1) ? seq_printf(m, "%d,", rs) : + seq_printf(m, "%d-%d,", rs, re - 1); + } + seq_puts(m, "\n"); +out: + put_task_struct(p); + + return 0; +} + +static int xcall_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, xcall_show, inode); +} + +static int xcall_enable_one(struct xcall_info *xinfo, unsigned int sc_no) +{ + test_and_set_bit(sc_no, xinfo->xcall_enable); + return 0; +} + +static int xcall_disable_one(struct xcall_info *xinfo, unsigned int sc_no) +{ + test_and_clear_bit(sc_no, xinfo->xcall_enable); + return 0; +} + +static ssize_t xcall_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct inode *inode = file_inode(file); + struct task_struct *p; + char buffer[TASK_COMM_LEN]; + const size_t maxlen = sizeof(buffer) - 1; + unsigned int sc_no = __NR_syscalls; + int ret = 0; + int is_clear = 0; + struct xcall_info *xinfo; + + if (!system_supports_xcall()) + return -EACCES; + + memset(buffer, 0, sizeof(buffer)); + if (!count || copy_from_user(buffer, buf, count > maxlen ? maxlen : count)) + return -EFAULT; + + p = get_proc_task(inode); + if (!p || !p->xinfo) + return -ESRCH; + + xinfo = p->xinfo; + if (buffer[0] == '!') + is_clear = 1; + + if (kstrtouint(buffer + is_clear, 10, &sc_no)) { + ret = -EINVAL; + goto out; + } + + if (sc_no >= __NR_syscalls) { + ret = -EINVAL; + goto out; + } + + if (!is_clear && !test_bit(sc_no, xinfo->xcall_enable)) + ret = xcall_enable_one(xinfo, sc_no); + else if (is_clear && test_bit(sc_no, xinfo->xcall_enable)) + ret = xcall_disable_one(xinfo, sc_no); + else + ret = -EINVAL; + +out: + put_task_struct(p); + + return ret ? ret : count; +} + +const struct file_operations proc_pid_xcall_operations = { + .open = xcall_open, + .read = seq_read, + .write = xcall_write, + .llseek = seq_lseek, + .release = single_release, +}; diff --git a/include/linux/sched.h b/include/linux/sched.h index 18361e35a377..fd975183ec26 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1478,7 +1478,7 @@ struct task_struct { KABI_RESERVE(14) #endif #if defined(CONFIG_FAST_SYSCALL) - KABI_USE(15, unsigned long *xcall_enable) + KABI_USE(15, struct xcall_info *xinfo) #else KABI_RESERVE(15) #endif diff --git a/kernel/fork.c b/kernel/fork.c index bd7afeb364ab..bbc3c5f147f0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -102,6 +102,9 @@ #include <linux/sched/grid_qos.h> #endif #include <linux/share_pool.h> +#ifdef CONFIG_FAST_SYSCALL +#include <asm/xcall.h> +#endif #include <asm/pgalloc.h> #include <linux/uaccess.h> #include <asm/mmu_context.h> @@ -481,8 +484,7 @@ void free_task(struct task_struct *tsk) sched_relationship_free(tsk); #ifdef CONFIG_FAST_SYSCALL - if (tsk->xcall_enable) - bitmap_free(tsk->xcall_enable); + xcall_task_free(tsk); #endif free_task_struct(tsk); @@ -1015,7 +1017,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) #endif #ifdef CONFIG_FAST_SYSCALL - tsk->xcall_enable = NULL; + tsk->xinfo = NULL; #endif return tsk; @@ -2097,12 +2099,9 @@ static __latent_entropy struct task_struct *copy_process( rt_mutex_init_task(p); #ifdef CONFIG_FAST_SYSCALL - p->xcall_enable = bitmap_zalloc(__NR_syscalls, GFP_KERNEL); - if (!p->xcall_enable) + retval = xcall_init_task(p, current); + if (retval) goto bad_fork_free; - - if (current->xcall_enable) - bitmap_copy(p->xcall_enable, current->xcall_enable, __NR_syscalls); #endif #ifdef CONFIG_QOS_SCHED_DYNAMIC_AFFINITY -- 2.34.1