One-Line Kernel Fix Ends Silent THP Data Loss Bug That Dated to 2023

An x86 pmd_modify() bug could drop the dirty bit on huge pages, letting reclaim free data written after MADV_FREE. Polars users lost production data. The fix is headed to stable kernels.
One-Line Kernel Fix Ends Silent THP Data Loss Bug That Dated to 2023
One-Line Kernel Fix Ends Silent THP Data Loss Bug That Dated to 2023

A one-line kernel fix merged after the Linux 7.3-rc3 release closes a bug that could silently throw away user-space data on x86 systems, Phoronix reported. The bug dates to July 2023 and has been present in every kernel since Linux 6.6.

It was reported at the start of September by Orson Peters, along with a small C program that reproduces it. With transparent huge pages (THP) enabled and the process under cgroup memory limits, writes made after a MADV_FREE call could be lost entirely, with no error.

That isn’t hypothetical. “Some of users of Polars (a data analytics library) have lost production data from this bug,” the commit message says. “They seem to have just the right combination of huge pages, MADV_FREE and heavy reclaim pressure.”

What went wrong

On x86, pmd_modify() masked the old page-table value with (_HPAGE_CHG_MASK & ~_PAGE_DIRTY), which discarded the hardware dirty bit. The pmd_mksaveddirty() call that follows is supposed to move that bit into _PAGE_SAVED_DIRTY when write-protecting, but by then there was nothing left to move. The equivalent pte_modify() and pud_modify() paths keep the dirty state; pmd_modify() was “the odd one out,” wrote patch author Vernon Yang.

In the reproducer, a program fills a THP-backed buffer, marks it with MADV_FREE, writes to it again, then toggles it read-only and back with mprotect(). The second write sets the dirty bit, but pmd_modify() drops it. Under memory pressure, reclaim finds the lazily freed folio with no dirty bit anywhere and frees it, so later reads get fresh zero pages instead of the data.

NUMA hinting alone can trigger the same loss, because do_huge_pmd_numa_page() also goes through pmd_modify(). PMD-mapped file THPs are affected too: if the dirty bit is dropped, rewritten data is never written back.

The fix

The patch changes the mask to plain _HPAGE_CHG_MASK, keeping _PAGE_DIRTY just as the PTE and PUD versions do, so the existing saved-dirty logic works as intended. It went in through the x86/urgent branch, was reviewed by Intel’s Rick Edgecombe, and is tagged for backport to supported stable kernels.

Operators running memory-limited containers with THP enabled, particularly analytics workloads like Polars, should pick up the next stable kernel update for their series.

Subscribe for Updates

DevNews Newsletter

The DevNews Email Newsletter is essential for software developers, web developers, programmers, and tech decision-makers. Perfect for professionals driving innovation and building the future of tech.

By signing up for our newsletter you agree to receive content related to ientry.com / webpronews.com and our affiliate partners. For additional information refer to our terms of service.

Notice an error?

Help us improve our content by reporting any issues you find.

Get the WebProNews newsletter delivered to your inbox

Get the free daily newsletter read by decision makers

Subscribe
Advertise with Us

Ready to get started?

Get our media kit

Advertise with Us