Skip to content

linux/mm/vmscan.c

Imported from _research/manual-study-linux/file-notes/linux__mm__vmscan.c.md.

File Notes: mm/vmscan.c

Status: reviewed.

Purpose

Implements page reclaim under memory pressure: scan-control policy, LRU isolation, inactive-list shrinking, folio writeback/unmap/free decisions, memcg-aware reclaim, direct reclaim, and background kswapd balancing.

Key Types And Functions

  • struct scan_control: per-reclaim invocation policy and accounting object.
  • shrink_folio_list(): core folio reclaim decision loop.
  • isolate_lru_folios(): moves folios from LRU lists to private scan lists.
  • shrink_inactive_list(): isolates inactive folios, calls reclaim, and moves unreclaimed folios back.
  • try_to_free_mem_cgroup_pages(): memcg reclaim entry.
  • kswapd_shrink_node(), balance_pgdat(), kswapd(), wakeup_kswapd(): background reclaim control path.

Data Flow

Reclaim begins with a scan_control describing how much to reclaim, which node or memcg to target, whether unmap/writepage/swap are allowed, what GFP context triggered pressure, and how much work has already been scanned or reclaimed.

Inactive-list reclaim isolates folios from an LRU vector, accounts the scan, passes the private list to shrink_folio_list(), and then returns unreclaimed folios to LRU state. shrink_folio_list() decides whether each folio can be locked, unmapped, written back, demoted, swapped, or freed. It handles writeback congestion, reference activation, anonymous swap allocation, dirty file writeback, pinned folios, and demotion fallback.

Background reclaim runs in kswapd(). Wakeups record the target node, order, and reclaim index. balance_pgdat() builds a scan-control instance, chooses priority and reclaim index, ages active lists, reclaims memcg soft-limit pages, shrinks nodes, wakes blocked direct reclaimers when watermarks improve, and decides whether to sleep or continue.

Invariants And Safety Contracts

  • Reclaim policy must respect may_writepage, may_unmap, and may_swap.
  • Folios are isolated before expensive reclaim work and either freed, demoted, or moved back to an LRU list.
  • Writeback and dirty-page handling avoid blocking in contexts that cannot write or wait.
  • Memcg reclaim tracks low-limit pressure and skipped groups separately from global reclaim.
  • kswapd operates with PF_MEMALLOC/PF_KSWAPD semantics because it exists to free memory for the system.

Rust Translation Guidance

A Rust reclaim loop should expose ScanControl as an immutable policy plus mutable counters, and model folios as state machines: isolated, locked, referenced, dirty, writeback, unmapped, demoted, freed, or returned. The code should make “cannot write”, “cannot unmap”, and “cannot swap” compile-visible policy constraints rather than hidden booleans passed through many helpers.

AI-Native Systems Guidance

Agent systems need equivalent pressure loops for context, cache, and embedding stores. Reclaim should isolate candidates, score references, checkpoint dirty state when allowed, demote cold data to cheaper storage, and wake blocked work only after watermarks improve.

Evidence

  • struct scan_control defines reclaim target, memcg, cost, permissions, priority, order, reclaim index, GFP mask, and counters at mm/vmscan.c:74-180.
  • shrink_folio_list() begins at mm/vmscan.c:1058-1060.
  • Its main loop locks folios, accounts scans, checks unevictable and unmap constraints, and classifies dirty/writeback state at mm/vmscan.c:1078-1132.
  • Writeback cases and throttling behavior are documented at mm/vmscan.c:1143-1188 and implemented at mm/vmscan.c:1189-1230.
  • Reference checks, demotion handling, swap allocation, unmap, pinned-folio, dirty-file, and writepage decisions run through mm/vmscan.c:1233-1441.
  • Demotion/free/move-back completion is handled near mm/vmscan.c:1553-1594.
  • isolate_lru_folios() is documented and implemented at mm/vmscan.c:1667-1780.
  • shrink_inactive_list() isolates LRU folios, calls shrink_folio_list(), and moves survivors back at mm/vmscan.c:1988-2055.
  • try_to_free_mem_cgroup_pages() builds memcg reclaim scan-control state and calls do_try_to_free_pages() at mm/vmscan.c:6767-6805.
  • kswapd_shrink_node() is at mm/vmscan.c:6996-7027.
  • balance_pgdat() sets up background reclaim policy and node balancing at mm/vmscan.c:7056-7290.
  • kswapd() runs the background reclaim thread at mm/vmscan.c:7391-7476.
  • wakeup_kswapd() records reclaim demand and wakes the daemon at mm/vmscan.c:7478-7528.