[PATCH 0/2] mm: don't apply task mempolicy to unmovable kernel allocations
From: Gregory Price
Date: Wed Jul 01 2026 - 18:21:46 EST
This series stops a task's NUMA mempolicy from steering incidental,
global kernel allocations that have no real relationship to the task.
VMA-less allocations (alloc_pages(), folio_alloc(), vmalloc(), slab
refils) - fall back to the current task's mempolicy as their only
placement hint.
This sweeps in kernel memory that is not the task's:
- unaccounted slab
- kernel page tables
- driver GFP_KERNEL buffers
- one-off global structures
- etc
On a uniform multi-socket system this is not implicitly harmful.
On a tiered-memory system a task's interleave/bind can push these
incidental allocations onto slower tiers and cause regressions.
The memory may outlive the task, or be shared by others, yet a single
task's policy dictated where it landed.
The fix is to only follow the task policy for allocations that are
plausibly the task's:
- movable allocations (mostly user data), and
- allocations explicitly tied to the task via __GFP_ACCOUNT.
Everything else (unmovable and unaccounted) prefers node-local.
Cpuset still enforces any hard confinements (ALLOC_CPUSET), and
fallback allocations may still cause spillage, but this at least
prevents interleave policies from making poor placements.
Patch 1 makes page-cache placement explicit in filemap to retain
existing behavior (pagecache and metadata still end up following
the task mempolicy). Since the metadata can be significant on
some systems, retaining this behavior will ensure there are no
surprises for existing users.
If we want to change this behavior, this patch is droppable.
Patch 2 adds the alloc_task_policy() filter for bare allocations.
Test 1: Page cache follows the task policy (unchanged)
======
A process running on node0 but bound to node1:
(numactl --cpunodebind=0 --membind=1) writes a 1.2G file.
membind=1 (non-local): FilePages node0 +0MB node1 +1200MB
membind=0 (control): FilePages node0 +1200MB node1 +0MB
Test 2: Incidental kernel allocations no longer follow it (changed)
======
Added a debugfs interface to do movable and kernel allocations:
w/ --cpunodebind=0
numactl ... --membind=1 echo 100000 > .../alloc_kernel
numactl ... --membind=1 echo 100000 > .../alloc_movable
numactl ... --interleave=all echo 100000 > .../alloc_kernel
GFP_KERNEL GFP_HIGHUSER_MOVABLE
membind=1 base: node1 (follows) node1
patched: node0 (local) node1 (follows)
interleave base: 50/50 (follows) 50/50
patched: node0 (local) 50/50 (follows)
Movable (user) allocations are unaffected in every case.
The unmovable unaccounted kernel allocations stop following the
task policy and place node-local. With no policy set, both place
node-local as before.
Suggested-by: Johannes Weiner <hannes@xxxxxxxxxxx>
Gregory Price (2):
mm/filemap: place page-cache folios via an explicit mempolicy
mm/mempolicy: skip task mempolicy for unmovable unaccounted kernel
allocations
mm/filemap.c | 5 ++++-
mm/mempolicy.c | 40 ++++++++++++++++++++++++++++------------
2 files changed, 32 insertions(+), 13 deletions(-)
--
2.53.0-Meta