From: David Stevens <stevensd@google.com>
To: Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>, Thomas Gleixner <tglx@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H . Peter Anvin" <hpa@zytor.com>,
Andrew Morton <akpm@linux-foundation.org>,
Dave Chinner <david@fromorbit.com>,
Qi Zheng <qi.zheng@linux.dev>,
Roman Gushchin <roman.gushchin@linux.dev>,
Muchun Song <muchun.song@linux.dev>,
Peter Zijlstra <peterz@infradead.org>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Steven Rostedt <rostedt@goodmis.org>,
Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
Valentin Schneider <vschneid@redhat.com>,
K Prateek Nayak <kprateek.nayak@amd.com>,
Uladzislau Rezki <urezki@gmail.com>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R . Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>, Kees Cook <kees@kernel.org>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Clark Williams <clrkwllms@kernel.org>,
suleiman@google.com
Cc: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
linux-rt-devel@lists.linux.dev,
David Stevens <stevensd@google.com>
Subject: [RFC 08/10] Set PF_RECLAIMABLE_STACK in various places
Date: Thu, 27 Aug 2026 16:29:46 -0700 [thread overview]
Message-ID: <20260827232948.2520558-9-stevensd@google.com> (raw)
In-Reply-To: <20260827232948.2520558-1-stevensd@google.com>
Annotate various blocking locations with the PF_RECLAIMABLE_STACK.
Signed-off-by: David Stevens <stevensd@google.com>
---
drivers/android/binder/thread.rs | 14 +++++++++++++
fs/eventpoll.c | 3 +++
fs/pipe.c | 28 ++++++++++++++++---------
fs/select.c | 3 +++
kernel/futex/waitwake.c | 3 +++
kernel/signal.c | 36 +++++++++++++++++++-------------
kernel/time/hrtimer.c | 3 +++
rust/kernel/task.rs | 16 ++++++++++++++
8 files changed, 82 insertions(+), 24 deletions(-)
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index bc0ef8927905..be62f7fd43ca 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -538,13 +538,21 @@ fn get_work_local(self: &Arc<Self>, wait: bool) -> Result<Option<DLArc<dyn Deliv
// Loop waiting only on the local queue (i.e., not registering with the process queue).
let mut inner = self.inner.lock();
+ // SAFETY: Only accessed locally in this function
+ let current = unsafe { Task::current() };
loop {
if let Some(work) = inner.pop_work() {
return Ok(Some(work));
}
inner.looper_flags |= LOOPER_WAITING;
+
+ current.set_flag_bits(bindings::PF_RECLAIMABLE_STACK);
+
let signal_pending = self.work_condvar.wait_interruptible_freezable(&mut inner);
+
+ current.clear_flag_bits(bindings::PF_RECLAIMABLE_STACK);
+
inner.looper_flags &= !LOOPER_WAITING;
if signal_pending {
@@ -592,15 +600,21 @@ fn get_work(self: &Arc<Self>, wait: bool) -> Result<Option<DLArc<dyn DeliverToRe
};
let mut inner = self.inner.lock();
+ // SAFETY: Only accessed locally in this function
+ let current = unsafe { Task::current() };
loop {
if let Some(work) = inner.pop_work() {
return Ok(Some(work));
}
+ current.set_flag_bits(bindings::PF_RECLAIMABLE_STACK);
+
inner.looper_flags |= LOOPER_WAITING | LOOPER_WAITING_PROC;
let signal_pending = self.work_condvar.wait_interruptible_freezable(&mut inner);
inner.looper_flags &= !(LOOPER_WAITING | LOOPER_WAITING_PROC);
+ current.clear_flag_bits(bindings::PF_RECLAIMABLE_STACK);
+
if signal_pending || inner.looper_need_return {
// We need to return now. We need to pull the thread off the list of ready threads
// (by dropping `reg`), then check the state again after it's off the list to
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index eed8cecd94e3..4e9c09446b48 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
+#include <linux/sched/task_stack.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/signal.h>
@@ -2302,6 +2303,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
if (signal_pending(current))
return -EINTR;
+ guard(allow_stack_reclaim)();
+
/*
* Internally init_wait() uses autoremove_wake_function(),
* thus wait entry is removed from the wait queue on each
diff --git a/fs/pipe.c b/fs/pipe.c
index 429b0714ec57..15503b12fe8f 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -27,6 +27,7 @@
#include <linux/watch_queue.h>
#include <linux/sysctl.h>
#include <linux/sort.h>
+#include <linux/sched/task_stack.h>
#include <linux/uaccess.h>
#include <asm/ioctls.h>
@@ -469,16 +470,23 @@ anon_pipe_read(struct kiocb *iocb, struct iov_iter *to)
break;
}
mutex_unlock(&pipe->mutex);
- /*
- * We only get here if we didn't actually read anything.
- *
- * But because we didn't read anything, at this point we can
- * just return directly with -ERESTARTSYS if we're interrupted,
- * since we've done any required wakeups and there's no need
- * to mark anything accessed. And we've dropped the lock.
- */
- if (wait_event_interruptible_exclusive(pipe->rd_wait, pipe_readable(pipe)) < 0)
- return -ERESTARTSYS;
+
+ {
+ guard(allow_stack_reclaim)();
+ /*
+ * We only get here if we didn't actually read
+ * anything.
+ *
+ * But because we didn't read anything, at this point
+ * we can just return directly with -ERESTARTSYS if
+ * we're interrupted, since we've done any required
+ * wakeups and there's no need to mark anything
+ * accessed. And we've dropped the lock.
+ */
+ if (wait_event_interruptible_exclusive(pipe->rd_wait,
+ pipe_readable(pipe)) < 0)
+ return -ERESTARTSYS;
+ }
wake_next_reader = true;
mutex_lock(&pipe->mutex);
diff --git a/fs/select.c b/fs/select.c
index 95d76531015a..3af1bf4d74a9 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/sched/rt.h>
+#include <linux/sched/task_stack.h>
#include <linux/syscalls.h>
#include <linux/export.h>
#include <linux/slab.h>
@@ -236,6 +237,8 @@ static int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
{
int rc = -EINTR;
+ guard(allow_stack_reclaim)();
+
set_current_state(state);
if (!READ_ONCE(pwq->triggered))
rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c
index d4483d15d30a..0fbf7bfcd904 100644
--- a/kernel/futex/waitwake.c
+++ b/kernel/futex/waitwake.c
@@ -2,6 +2,7 @@
#include <linux/plist.h>
#include <linux/sched/task.h>
+#include <linux/sched/task_stack.h>
#include <linux/sched/signal.h>
#include <linux/freezer.h>
@@ -378,6 +379,7 @@ void futex_do_wait(struct futex_q *q, struct hrtimer_sleeper *timeout)
* has tried to wake us, and we can skip the call to schedule().
*/
if (likely(!plist_node_empty(&q->list))) {
+ guard(allow_stack_reclaim)();
/*
* If the timer has already expired, current will already be
* flagged for rescheduling. Only call schedule if there
@@ -547,6 +549,7 @@ static void futex_sleep_multiple(struct futex_vector *vs, unsigned int count,
return;
}
+ guard(allow_stack_reclaim)();
schedule();
}
diff --git a/kernel/signal.c b/kernel/signal.c
index bbc0fd4cc4d7..ca0d79ee013f 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2718,17 +2718,21 @@ static void do_freezer_trap(void)
return;
}
- /*
- * Now we're sure that there is no pending fatal signal and no
- * pending traps. Clear TIF_SIGPENDING to not get out of schedule()
- * immediately (if there is a non-fatal signal pending), and
- * put the task into sleep.
- */
- __set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
- clear_thread_flag(TIF_SIGPENDING);
- spin_unlock_irq(¤t->sighand->siglock);
- cgroup_enter_frozen();
- schedule();
+ {
+ guard(allow_stack_reclaim)();
+
+ /*
+ * Now we're sure that there is no pending fatal signal and no
+ * pending traps. Clear TIF_SIGPENDING to not get out of schedule()
+ * immediately (if there is a non-fatal signal pending), and
+ * put the task into sleep.
+ */
+ __set_current_state(TASK_INTERRUPTIBLE | TASK_FREEZABLE);
+ clear_thread_flag(TIF_SIGPENDING);
+ spin_unlock_irq(¤t->sighand->siglock);
+ cgroup_enter_frozen();
+ schedule();
+ }
/*
* We could've been woken by task_work, run it to clear
@@ -3788,9 +3792,13 @@ static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info,
recalc_sigpending();
spin_unlock_irq(&tsk->sighand->siglock);
- __set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
- ret = schedule_hrtimeout_range(to, tsk->timer_slack_ns,
- HRTIMER_MODE_REL);
+ {
+ guard(allow_stack_reclaim)();
+ __set_current_state(TASK_INTERRUPTIBLE | TASK_FREEZABLE);
+ ret = schedule_hrtimeout_range(to, tsk->timer_slack_ns,
+ HRTIMER_MODE_REL);
+ }
+
spin_lock_irq(&tsk->sighand->siglock);
__set_task_blocked(tsk, &tsk->real_blocked);
sigemptyset(&tsk->real_blocked);
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 313dcea127fe..30c85482dfd5 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -39,6 +39,7 @@
#include <linux/sched/nohz.h>
#include <linux/sched/debug.h>
#include <linux/sched/isolation.h>
+#include <linux/sched/task_stack.h>
#include <linux/timer.h>
#include <linux/freezer.h>
#include <linux/compat.h>
@@ -2392,6 +2393,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
struct restart_block *restart;
do {
+ guard(allow_stack_reclaim)();
+
set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
hrtimer_sleeper_start_expires(t, mode);
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index 38273f4eedb5..6168f058343a 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -344,6 +344,22 @@ pub fn group_leader(&self) -> &Task {
// only be used while `current` is still valid, thus still running.
unsafe { &*ptr.cast() }
}
+
+ /// Sets the given task flag bits on the current task.
+ #[inline]
+ pub fn set_flag_bits(&self, set: u32) {
+ // SAFETY: The `flags` field of `current` is not modified from other threads, so
+ // the non-atomic update isn't a race.
+ unsafe { (*self.as_ptr()).flags |= set }
+ }
+
+ /// Clears the given task flag bits on the current task.
+ #[inline]
+ pub fn clear_flag_bits(&self, clear: u32) {
+ // SAFETY: The `flags` field of `current` is not modified from other threads, so
+ // the non-atomic update isn't a race.
+ unsafe { (*self.as_ptr()).flags &= !clear }
+ }
}
// SAFETY: The type invariants guarantee that `Task` is always refcounted.
--
2.55.0.897.gb25b4bd76c-goog
next prev parent reply other threads:[~2026-08-27 23:31 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 23:29 [RFC 00/10] Reclaimable kernel stacks David Stevens
2026-08-27 23:29 ` [RFC 01/10] Add !MEMCG memcg_list_lru_alloc implementation David Stevens
2026-08-27 23:29 ` [RFC 02/10] mm/vmalloc: Skip vmallocinfo NUMA stats for VM_SPARSE David Stevens
2026-08-27 23:29 ` [RFC 03/10] fork: refactor vmap stack alloc/free into helpers David Stevens
2026-08-27 23:29 ` [RFC 04/10] mm: vmalloc: support creating aligned vm areas David Stevens
2026-08-27 23:29 ` [RFC 05/10] fork: allocate reclaimable stacks with VM_SPARSE David Stevens
2026-08-27 23:29 ` [RFC 06/10] Reclaim memory from blocked kernel stacks David Stevens
2026-08-27 23:53 ` sashiko-bot
2026-08-28 11:54 ` Peter Zijlstra
2026-08-28 12:01 ` Peter Zijlstra
2026-08-28 12:04 ` Peter Zijlstra
2026-08-29 0:18 ` David Stevens
2026-08-28 12:41 ` Peter Zijlstra
2026-08-28 12:57 ` Peter Zijlstra
2026-08-28 23:33 ` David Stevens
2026-08-28 13:36 ` Sebastian Andrzej Siewior
2026-08-28 13:59 ` Peter Zijlstra
2026-08-28 14:25 ` Peter Zijlstra
2026-08-28 15:58 ` Sebastian Andrzej Siewior
2026-08-28 15:10 ` Sebastian Andrzej Siewior
2026-08-28 19:08 ` Steven Rostedt
2026-08-28 19:13 ` Steven Rostedt
2026-08-28 19:17 ` Steven Rostedt
2026-08-28 20:50 ` David Stevens
2026-08-28 21:17 ` David Stevens
2026-08-27 23:29 ` [RFC 07/10] Reclaim stacks via a shrinker David Stevens
2026-08-27 23:29 ` David Stevens [this message]
2026-08-27 23:43 ` [RFC 08/10] Set PF_RECLAIMABLE_STACK in various places sashiko-bot
2026-08-28 6:33 ` K Prateek Nayak
2026-08-27 23:29 ` [RFC 09/10] x86: Enable reclaimable stacks David Stevens
2026-08-27 23:29 ` [RFC 10/10] arm64: " David Stevens
2026-08-28 12:47 ` [RFC 00/10] Reclaimable kernel stacks Peter Zijlstra
2026-08-28 14:33 ` Steven Rostedt
2026-08-28 14:35 ` Peter Zijlstra
2026-08-28 14:45 ` Peter Zijlstra
2026-08-28 16:10 ` Steven Rostedt
2026-08-28 17:58 ` David Stevens
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260827232948.2520558-9-stevensd@google.com \
--to=stevensd@google.com \
--cc=akpm@linux-foundation.org \
--cc=bigeasy@linutronix.de \
--cc=bp@alien8.de \
--cc=bsegall@google.com \
--cc=catalin.marinas@arm.com \
--cc=clrkwllms@kernel.org \
--cc=dave.hansen@linux.intel.com \
--cc=david@fromorbit.com \
--cc=david@kernel.org \
--cc=dietmar.eggemann@arm.com \
--cc=hpa@zytor.com \
--cc=juri.lelli@redhat.com \
--cc=kees@kernel.org \
--cc=kprateek.nayak@amd.com \
--cc=liam@infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=ljs@kernel.org \
--cc=mgorman@suse.de \
--cc=mhocko@suse.com \
--cc=mingo@redhat.com \
--cc=muchun.song@linux.dev \
--cc=peterz@infradead.org \
--cc=qi.zheng@linux.dev \
--cc=roman.gushchin@linux.dev \
--cc=rostedt@goodmis.org \
--cc=rppt@kernel.org \
--cc=suleiman@google.com \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=urezki@gmail.com \
--cc=vbabka@kernel.org \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=will@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox