Re: [RFC 06/10] Reclaim memory from blocked kernel stacks

From: David Stevens

Date: Mon Aug 31 2026 - 16:35:18 EST


On Sat, Aug 29, 2026 at 1:39 AM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:
>
> On Fri, Aug 28, 2026 at 05:18:05PM -0700, David Stevens wrote:
> > On Fri, Aug 28, 2026 at 5:04 AM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:
> > >
> > > On Thu, Aug 27, 2026 at 04:29:44PM -0700, David Stevens wrote:
> > > > @@ -4320,8 +4319,18 @@ int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
> > > > * A similar smp_rmb() lives in __task_needs_rq_lock().
> > > > */
> > > > smp_rmb();
> > > > - if (READ_ONCE(p->on_rq) && ttwu_runnable(p, wake_flags))
> > > > + if (READ_ONCE(p->on_rq) && ttwu_runnable(p, wake_flags)) {
> > > > + trace_sched_waking(p);
> > > > + break;
> > > > + }
> > > > +
> > > > + if (!ensure_stack_is_present(p, &need_deferred_repopulate)) {
> > > > + WRITE_ONCE(p->__state, TASK_STACK_RECLAIM);
> > > > + do_deferred_repopulate_wake = need_deferred_repopulate;
> > > > break;
> > > > + }
> > > > +
> > > > + trace_sched_waking(p);
> > >
> > > Absolutely not; ensure_stack_is_present() must not call
> > > repopulate_stack() while holding ->pi_lock. Not happening.
> >
> > The optimistic fast path for repopulate_stack() could be modified to
> > try pulling from a pre-allocated pool of zero'ed pages. That would
> > reduce the function to a couple of memcg_kmem_charge_page() calls and
>
> Afaict memcg_kmem_charge_page() ends up in a local_lock, which is a
> spinlock, so that cannot be.
>
> Most, if not everything, in mm/ is build around being preemptible and
> thus not suitable for use under raw_spinlock_t.

With the recent work to make memcg charging NMI safe, I had thought
that charging from within the scheduler would be safe. However, you're
right that the fast path does call local_trylock(). I didn't realize
that only works because of an in_nmi() check inside local_trylock().

Given that NMI safe charging requires only using trylock and handling
the !trylock case, it's not infeasible to have an implementation that
always skips the trylocks.

The alternatives to that would be either not uncharging on unmap, as
suggested further down the thread, or using deferred charging.
However, both of those approaches would make memcg charging less
accurate, which is not desirable.

> > then vmap_pages_range() to repopulate the stack's page tables. That
>
> vmap_page_range() can end up in the allocator, which I suppose is ruled
> out by the vmap having been populated before, but it still has a
> might_sleep() that will scream AFAICT.

It looks like when we go through vmap_small_pages_range_noflush(), the
might_sleep() check is missing. That would explain why I haven't been
seeing errors.

We wouldn't want to remove that might_sleep(), so I guess this would
require either a new function or flag to support mapping into existing
page tables.


-David