2. Memory Management

Fix the Bug: Two-List LRU Page Reclaim

midmemory-managementcaching

Linux's page cache doesn't use a single LRU list -- it uses TWO: an inactive list and an active list. New pages start on inactive. Reclaim (evicting pages under memory pressure) always scans inactive first, never touching active. A page only earns promotion to active -- and the real protection that comes with it -- after a second reference while it's still sitting on inactive.

This is deliberately different from a single-list LRU (compare the Database Internals course's "LRU Buffer Pool" exercise, which is exactly that): the point of splitting into two lists is scan resistance. A one-off sequential scan (grep -r walking a huge source tree) touches millions of pages exactly once each -- with a single LRU list, that scan would evict your entire actually hot working set, since plain "most-recently-used" can't distinguish a genuinely hot page from a page touched once by an unrelated scan. Requiring a second touch before a page earns real protection fixes that.

TwoListLRU in the starter code passes basic get/put smoke tests, but a teammate noticed something worse under load: pages that are clearly "hot" (repeatedly re-read) sometimes get evicted anyway, while pages touched exactly once during a one-time scan stick around indefinitely -- the opposite of what scan resistance is supposed to guarantee. Find and fix the bug in _touch.

Constraints

  • The fix is local to _touch -- get, put, and _reclaim are already correct.
  • A page's first reference while on inactive must NOT promote it -- it should only be flagged (added to self.referenced). Promotion happens on the reference AFTER that, while the page is still on inactive.
  • A page already on active still just refreshes its position on any reference (this part of _touch is correct in the starter).

Real-world grounding

  • The active/inactive list split and its reclaim-scans-inactive-first policy: mm/vmscan.c (see shrink_active_list(), and the LRU_ACTIVE/LRU_INACTIVE list enum used throughout).
  • The "second reference promotes" logic (folio_mark_accessed(), which sets a PG_referenced flag on a first hit and only moves the folio to the active list on a subsequent one): mm/folio.c

Real Linux adds more refinements on top of this same two-list skeleton -- separate LRU lists per memory cgroup and NUMA node, a distinction between file-backed and anonymous pages, and (in very recent kernels) a multi-generational LRU that generalizes "two lists" into several generations -- but the core defining rule this exercise tests (single touch does not protect a page; a second touch does) is the same one that motivated the original active/inactive split.

hints
page_reclaim.pysign in to run
Loading...
test result

This is a preview. Sign in to run this exercise against the real tests.