[PATCH 2/8] exec: add a speculate-or-lock helper for exec_update readers

From: Christian Brauner

Date: Mon May 25 2026 - 03:26:54 EST


The exec_update_seq readers share one control flow: try a lockless
seqcount read and fall back to exec_update_lock if a writer (exec or
Landlock TSYNC) is in flight. Rather than open-code it in every reader,
add a trio modeled on read_seqbegin_or_lock() / need_seqretry() /
done_seqretry() (seqlock.h), adapted for exec_update_seq paired with the
killable exec_update_lock:

exec_update_read_begin_or_lock() - lockless first pass (seq even); on a
racing writer escalate to down_read_killable() (seq odd); -EINTR if
killed while waiting.
exec_update_read_needs_retry() - true if the lockless pass raced, in
which case the caller drops any ref taken, sets seq = 1, and retries.
exec_update_read_done() - releases exec_update_lock if taken.

No users yet; no functional change.

Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
include/linux/sched/signal.h | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 952f0368f201..0c1bb3b530e4 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -311,6 +311,36 @@ static inline bool exec_update_speculate_retry(struct signal_struct *sig,
return read_seqcount_retry(&sig->exec_update_seq, seq);
}

+/* Speculate-or-lock exec_update reader, mirroring read_seqbegin_or_lock(). */
+static inline int exec_update_read_begin_or_killable(struct signal_struct *sig,
+ unsigned int *seq)
+{
+ int ret;
+
+ if (!(*seq & 1)) {
+ if (exec_update_speculate_try_begin(sig, seq))
+ return 0;
+ *seq = 1;
+ }
+ ret = down_read_killable(&sig->exec_update_lock);
+ if (ret)
+ *seq = 0;
+ return ret;
+}
+
+static inline bool exec_update_read_needs_retry(struct signal_struct *sig,
+ unsigned int seq)
+{
+ return !(seq & 1) && exec_update_speculate_retry(sig, seq);
+}
+
+static inline void exec_update_read_done(struct signal_struct *sig,
+ unsigned int seq)
+{
+ if (seq & 1)
+ up_read(&sig->exec_update_lock);
+}
+
extern void flush_signals(struct task_struct *);
extern void ignore_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
--
2.47.3


--j3ezp33mpunnwnqz
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-mm-take-a-lock-free-exec_update_seq-fast-path-in-mm_.patch"