Re: [RFC PATCH v11 0/4] mm/swap: priority-based swap tiers with per-cgroup selection

From: Youngjun Park

Date: Sun Sep 20 2026 - 12:23:27 EST


On 2026-09-16 16:04, Johannes Weiner wrote:
> On Thu, Sep 17, 2026 at 03:34:33AM +0900, Youngjun Park wrote:
> > Per-cgroup swap in debugfs
> > ==========================
> >
> > Patches 3 and 4 let a memory cgroup choose its tiers through debugfs.
> >
> > # swapon -p 100 /dev/nvme0n1p2
> > # swapon -p 50 /dev/sdb2
> > # cat /sys/kernel/debug/swap/tiers
> > Idx Prio
> > 0 100
> > 1 50
> > # echo "/batch 0x2" > /sys/kernel/debug/swap/memcg_tiers
> >
> > Bit i of the mask is tier i, so /batch swaps only to sdb2. A tier keeps
> > its index for its lifetime, so the mask keeps selecting the same tier
> > across swapon and swapoff.
>

Hello Johannes,

Sorry for the late reply on a good suggestion :)

> Can the cgroup be given a priority limit? That would have pretty
> obvious inheritance semantics:
> root
> `- batch (memory.swap.prio.max = 20)
> `- task (memory.swap.prio.max = max)
> `- logs (memory.swap.prio.max = 10)
> `- interactive (memory.swap.prio.max = max)
> `- task (memory.swap.prio.max)

Right, the inheritance is clear and easy to understand, and with this I
can pre-define the limit without knowing the mask value.

But first, let me check the intent. Is the point that capping batch keeps
it from taking the faster tiers, so they are left for interactive?

If so, that matches our use case. Latency sensitive workloads get the
fast tiers, non-latency sensitive ones get the slow tiers. But...

Even then, the reverse cannot be expressed. A cap only cuts from the top,
so a latency sensitive workload given max can still fall back to the slow
tiers once the fast ones fill up. For example,

tier0 tier1 tier2 tier3
0 10 20 30

there is no way to say "use tier0 and tier1, but never fall back to tier2
or tier3". To cover that, the interface would also need a min value, or
some way to express a range.

And even a range is not enough. Excluding only tier2 leaves a hole in the
middle, which no min/max pair can express. That needs per-tier selection,
which is what the mask, and what I'd carry over to the memcg
interface later (Currently memcg.swap.tiers.max).

How do you think?

Thanks!
Youngjun Park