[RFC PATCH 01/10] thread_info: add helpers to snapshot thread flags

From: Mark Rutland
Date: Wed Jun 09 2021 - 08:20:23 EST


We have common helpers to manipulate individual thread flags, but where
code wants to check several flags at once, it must open code reading
current_thread_info()->flags and operating on a snapshot.

As some flags can be set remotely it's necessary to use READ_ONCE() to
get a consistent snapshot even when IRQs are disabled, but some code
forgets to do this. Generally this is unlike to cause a problem in
practice, but it is somewhat unsound, and KCSAN will legitimately warn
that there is a data race.

To make it easier to do the right thing, and to highlight that
concurrent modification is possible, let's add a new helpers to snapshot
the flags, which should be used in preference to plain reads.
Subsequent patches will move existing code to use the new helpers.

Signed-off-by: Mark Rutland <mark.rutland@xxxxxxx>
Cc: Boqun Feng <boqun.feng@xxxxxxxxx>
Cc: Dmitry Vyukov <dvyukov@xxxxxxxxxx>
Cc: Marco Elver <elver@xxxxxxxxxx>
Cc: Paul E. McKenney <paulmck@xxxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Will Deacon <will@xxxxxxxxxx>
---
include/linux/thread_info.h | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index 157762db9d4b..f3769842046d 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -117,6 +117,11 @@ static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
return test_bit(flag, (unsigned long *)&ti->flags);
}

+static 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) \
@@ -129,6 +134,11 @@ static inline int test_ti_thread_flag(struct thread_info *ti, int 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())
+
+#define read_task_thread_flags(t) \
+ read_ti_thread_flags(task_thread_info(t))

#ifdef CONFIG_GENERIC_ENTRY
#define set_syscall_work(fl) \
--
2.11.0