From: Yury Norov ynorov@caviumnetworks.com
maillist inclusion category: feature bugzilla: 46790 CVE: NA
Reference: https://github.com/norov/linux/commits/ilp32-5.2
--------------------------------
Thread bits may be accessed from low-level code, so isolating is a measure to avoid circular dependencies in header files.
The exact reason for circular dependency is WARN_ON() macro added in patch edd63a27 "set_restore_sigmask() is never called without SIGPENDING (and never should be)"
Signed-off-by: Yury Norov ynorov@caviumnetworks.com Signed-off-by: Yury Norov ynorov@marvell.com Signed-off-by: Xiongfeng Wang wangxiongfeng2@huawei.com Acked-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Chen Jun chenjun102@huawei.com
Conflicts: include/linux/sched.h include/linux/thread_info.h [chenjiahao: small context conflicts because of inclusion of header files]
Signed-off-by: Chen Jiahao chenjiahao16@huawei.com --- include/linux/sched.h | 1 + include/linux/thread_bits.h | 87 +++++++++++++++++++++++++++++++++++++ include/linux/thread_info.h | 73 +------------------------------ 3 files changed, 89 insertions(+), 72 deletions(-) create mode 100644 include/linux/thread_bits.h
diff --git a/include/linux/sched.h b/include/linux/sched.h index eed5d65b8d1f..b92a6c197d0d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -38,6 +38,7 @@ #include <linux/rv.h> #include <linux/livepatch_sched.h> #include <asm/kmap_size.h> +#include <linux/thread_bits.h>
/* task_struct member predeclarations (sorted alphabetically): */ struct audit_context; diff --git a/include/linux/thread_bits.h b/include/linux/thread_bits.h new file mode 100644 index 000000000000..0f6fe55744f1 --- /dev/null +++ b/include/linux/thread_bits.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Common low-level thread bits accessors */ + +#ifndef _LINUX_THREAD_BITS_H +#define _LINUX_THREAD_BITS_H + +#ifndef __ASSEMBLY__ + +/* + * For per-arch arch_within_stack_frames() implementations, defined in + * asm/thread_info.h. + */ +enum { + BAD_STACK = -1, + NOT_STACK = 0, + GOOD_FRAME, + GOOD_STACK, +}; + +#ifdef CONFIG_THREAD_INFO_IN_TASK +/* + * For CONFIG_THREAD_INFO_IN_TASK kernels we need <asm/current.h> for the + * definition of current, but for !CONFIG_THREAD_INFO_IN_TASK kernels, + * including <asm/current.h> can cause a circular dependency on some platforms. + */ +#include <asm/current.h> +#define current_thread_info() ((struct thread_info *)current) +#endif + +#include <linux/bitops.h> +#include <asm/thread_info.h> + +/* + * flag set/clear/test wrappers + * - pass TIF_xxxx constants to these functions + */ + +static inline void set_ti_thread_flag(struct thread_info *ti, int flag) +{ + set_bit(flag, (unsigned long *)&ti->flags); +} + +static inline void clear_ti_thread_flag(struct thread_info *ti, int flag) +{ + clear_bit(flag, (unsigned long *)&ti->flags); +} + +static inline void update_ti_thread_flag(struct thread_info *ti, int flag, + bool value) +{ + if (value) + set_ti_thread_flag(ti, flag); + else + clear_ti_thread_flag(ti, flag); +} + +static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag) +{ + return test_and_set_bit(flag, (unsigned long *)&ti->flags); +} + +static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag) +{ + return test_and_clear_bit(flag, (unsigned long *)&ti->flags); +} + +static inline int test_ti_thread_flag(struct thread_info *ti, int flag) +{ + return test_bit(flag, (unsigned long *)&ti->flags); +} + +#define set_thread_flag(flag) \ + set_ti_thread_flag(current_thread_info(), flag) +#define clear_thread_flag(flag) \ + clear_ti_thread_flag(current_thread_info(), flag) +#define update_thread_flag(flag, value) \ + update_ti_thread_flag(current_thread_info(), flag, value) +#define test_and_set_thread_flag(flag) \ + test_and_set_ti_thread_flag(current_thread_info(), flag) +#define test_and_clear_thread_flag(flag) \ + test_and_clear_ti_thread_flag(current_thread_info(), flag) +#define test_thread_flag(flag) \ + test_ti_thread_flag(current_thread_info(), flag) + +#endif /* !__ASSEMBLY__ */ +#endif /* _LINUX_THREAD_BITS_H */ diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index c02646884fa8..401e4553cb7d 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -13,30 +13,10 @@ #include <linux/bug.h> #include <linux/restart_block.h> #include <linux/errno.h> - -#ifdef CONFIG_THREAD_INFO_IN_TASK -/* - * For CONFIG_THREAD_INFO_IN_TASK kernels we need <asm/current.h> for the - * definition of current, but for !CONFIG_THREAD_INFO_IN_TASK kernels, - * including <asm/current.h> can cause a circular dependency on some platforms. - */ -#include <asm/current.h> -#define current_thread_info() ((struct thread_info *)current) -#endif +#include <linux/thread_bits.h>
#include <linux/bitops.h>
-/* - * For per-arch arch_within_stack_frames() implementations, defined in - * asm/thread_info.h. - */ -enum { - BAD_STACK = -1, - NOT_STACK = 0, - GOOD_FRAME, - GOOD_STACK, -}; - #ifdef CONFIG_GENERIC_ENTRY enum syscall_work_bit { SYSCALL_WORK_BIT_SECCOMP, @@ -79,45 +59,6 @@ static inline long set_restart_fn(struct restart_block *restart,
#define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO)
-/* - * flag set/clear/test wrappers - * - pass TIF_xxxx constants to these functions - */ - -static inline void set_ti_thread_flag(struct thread_info *ti, int flag) -{ - set_bit(flag, (unsigned long *)&ti->flags); -} - -static inline void clear_ti_thread_flag(struct thread_info *ti, int flag) -{ - clear_bit(flag, (unsigned long *)&ti->flags); -} - -static inline void update_ti_thread_flag(struct thread_info *ti, int flag, - bool value) -{ - if (value) - set_ti_thread_flag(ti, flag); - else - clear_ti_thread_flag(ti, flag); -} - -static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag) -{ - return test_and_set_bit(flag, (unsigned long *)&ti->flags); -} - -static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag) -{ - return test_and_clear_bit(flag, (unsigned long *)&ti->flags); -} - -static inline int test_ti_thread_flag(struct thread_info *ti, int flag) -{ - return test_bit(flag, (unsigned long *)&ti->flags); -} - /* * This may be used in noinstr code, and needs to be __always_inline to prevent * inadvertent instrumentation. @@ -127,18 +68,6 @@ static __always_inline unsigned long read_ti_thread_flags(struct thread_info *ti return READ_ONCE(ti->flags); }
-#define set_thread_flag(flag) \ - set_ti_thread_flag(current_thread_info(), flag) -#define clear_thread_flag(flag) \ - clear_ti_thread_flag(current_thread_info(), flag) -#define update_thread_flag(flag, value) \ - update_ti_thread_flag(current_thread_info(), flag, value) -#define test_and_set_thread_flag(flag) \ - test_and_set_ti_thread_flag(current_thread_info(), flag) -#define test_and_clear_thread_flag(flag) \ - test_and_clear_ti_thread_flag(current_thread_info(), flag) -#define test_thread_flag(flag) \ - test_ti_thread_flag(current_thread_info(), flag) #define read_thread_flags() \ read_ti_thread_flags(current_thread_info())