patch review and learn
- The state of the page in 2025(LSFMM 2025)
- 在 2025 年,目标是让 struct folio 确实成为一个与 struct page 分离的结构,并且可以独立分配。然后,可以从 struct page 中移除一些数据,缩小它,但还不能完全移除。
- MatthewWilcox/Memdescs/Path - Linux Kernel Newbies
- MatthewWilcox/BuddyAllocator - Linux Kernel Newbies
- 2010-11-03 [PATCH 00 of 66] Transparent Hugepage Support #32 - Andrea Arcangeli
- 支持 anon THP
- v33 https://lore.kernel.org/all/20101215051540.GP5638@random.random/
- thp: transparent hugepage core
- 处理 anon page fault 时,会预先分配好一个 PTE pagetable,存放到 mm_struct 粒度的链表里。现在这个函数叫做
pgtable_trans_huge_deposit()
,与之相对应的函数是pgtable_trans_huge_withdraw()
,即存款和提款。 - zap_huge_pmd() 时,会把这个预留的 pagetalbe 释放掉。
- 处理 anon page fault 时,会预先分配好一个 PTE pagetable,存放到 mm_struct 粒度的链表里。现在这个函数叫做
- 2014-11-11 Transparent huge page reference counting [LWN.net]
- 2015-10-06 [PATCHv12 00/37] THP refcounting redesign - Kirill A. Shutemov
- 新的 refcount mapcout 方案
- anon THP 同时存在 PMD map 和 PTE map 时,会给所有 subpage 的 mapcount +1,这是为了保证 atomici page_remove_rmap();并且,还会加上 PG_double_map bit,用于在 page_remove_rmap() 时判断是否同时存在 anon THP 的 PMD map 和 PTE map,如果同时存在,并且此时正在 remove 最后一个 PMD map 了,就需要把之前给所有 subpage +1 的 mapcount 给 -1 回来。
- 支持 THP 的 PMD map 和 PTE map 共存
- [PATCHv12 29/37] thp: implement split_huge_pmd() 新的 PMD 页表拆分实现
- 会 page_ref_add(page, HPAGE_PMD_NR - 1); 这是因为多出了 512 个 PTE 映射,少了 1 个 PMD 映射,而对 subpage 进行 get_page() 实际上是对 head page 操作的。
- [PATCHv12 30/37] thp: add option to setup migration entries during PMD split
- PATCH RFC 和之前一样依赖于 compound_lock()
- 从 PATCHv2 开始,则是通过 migration PTE entries 来 stabilize page counts,也就是把页面放进 swapcache?和 try_to_unmap 差不多。
- [PATCHv12 32/37] thp: reintroduce split_huge_page() 新的 THP 大页拆分实现
- 持有 anon_vma 锁,因为接下来我们要 rmap walk 了
- 检查是不是只有 caller 有额外的一个 refcount(也就是除了与 mapcount 一一对应的 refcount 以外,还有其他的 refcount,这也意味着现在页面被 pin 住了无法 migrate)
freeze_page()
:这个函数名不够好,其实就是反向映射,并做页表拆分- 遍历 anon_vma 区间树,找到所有映射了该大页的 PMD 虚拟地址
freeze_page_vma()
拆分 PMD 页表。有可能已经 swap out 了,页表已经拆分了,这时则是处理这些 PTE swap entry。
- [PATCHv12 34/37] thp: introduce deferred_split_huge_page() 首次支持延迟拆分大页。如果某个 THP 已经不存在 PMD map,如果其中某些 subpage 不存在 PTE map,那么这些 subpage 也许是可以被释放的(之所以说“也许”,是因为还要考虑到 refcount),这就需要先 split THP 拆成小页,然后才能释放。这个 patch 做的事情:在 subpage 也许可以被释放时,把要拆分的 THP 放进一个队列,等内存回收时由 shrinker 来释放。
- 在 page_remove_rmap() PMD page 时,如果这是最后一个 unmap 的大页,并且有 nr 个 subpage 没有 PTE map,说明这 nr 个 subpage 可以被释放,把 THP 放进队列。
- 在 page_remove_rmap() subpage 时,如果 unmap 该 subpage 后,该 subpage 的 mapcount 为 -1,这说明,首先,已经没有 PageDoubleMap 带来的 1 个 mapcount,即,该 THP 没有 PMD map 了,另外,还说明该 subpage 没有 PTE map 了。于是把 THP 放进队列。
- 定义了一个 deferred_split_shrinker
- 在拆分 THP 时,如果该大页在队列内,则将其从队列中移除。
- 对 mlocked THP 的处理
- 新的 refcount mapcout 方案
- 2016-03-07 [PATCHv2 0/4] thp: simplify freeze_page() and unfreeze_page() - Kirill A. Shutemov
- 在大页拆分时,使用通用的 rmap walker
try_to_unmap()
,简化了freeze_page()
和unfreeze_page()
- try_to_unmap() 见 https://www.cnblogs.com/tolimit/p/5432674.html
- TTU_SPLIT_HUGE_PMD 会让 try_to_unmap() 时先 split_huge_pmd_address() 拆分 PMD 页表。注意每次调用 try_to_unmap() 只会 unmap 一个 page 的所有反向映射,所以要调用 HPAGE_PMD_NR 次。
- 在大页拆分时,使用通用的 rmap walker
- 2016-05-11 Transparent huge pages in the page cache [LWN.net]
- 2016-06-15 [PATCHv9 00/32] THP-enabled tmpfs/shmem using compound pages - Kirill A. Shutemov
- 支持 tmpfs/shmem THP
- [PATCHv9 05/32] rmap: support file thp
-
page_add_file_rmap()
对于 THP 会把每个 subpage 的 mapcount 都 +1。不理解为什不能和page_add_anon_rmap()
一样,commit message 里说是后续再优化。 - 不理解。PG_double_map 的优化对 file page 无效,这是因为 lifecycle 与 anon page 不同,file page 在没有 map 时还可以继续存在,随时再次被 map。
-
- thp: support file pages in zap_huge_pmd()
- thp: handle file pages in split_huge_pmd()
- 只做了 unmap,没有像 anon page 那样分配页表去填 PTE,因为 file page 可以等到 page fault 时再去填 PTE 页表。不理解,如果填 PTE 页表,避免后续可能的 pagefault 不是很好吗?
- thp: handle file COW faults
- split huge pmd 然后在 pte level 处理。因为不清楚在 private file page CoW 场景分配 huge page 的收益如何,可能是过度设计。
- thp: skip file huge pmd on copy_huge_pmd()
- 典型场景:进程 clone。对于 file pages,可以不 alloc pagetable,不 copy pte/pmd,可以在 pagefault 时做。copy_huge_pmd() 的调用路径只有 copy_page_range(),后者会使得没有 vma->anon_vma 的跳过 copy pte/pmd。但是因为 private file mapping 是可以有 anon_vma 的,所以没有跳过,这里选择了让 copy_huge_pmd() 通过 vma->vm_ops 把这种情况检查出来,跳过 private file huge pmd 的 copy。
- thp: file pages support for split_huge_page()
- vmscan: split file huge pages before paging them out
- filemap: prepare find and delete operations for huge pages
- shmem: add huge pages support
- 2022-11-03 [PATCH 0/3] mm,huge,rmap: unify and speed up compound mapcounts - Hugh Dickins
- 优化 compound mapcount
- mm,thp,rmap: simplify compound page mapcount handling
- 2022-11-22 [PATCH v2 0/3] mm,thp,rmap: rework the use of subpages_mapcount - Hugh Dickins
- 2024-04-09 [PATCH v1 00/18] mm: mapcount for large folios + page_mapcount() cleanups - David Hildenbrand
- 2023-07-10 [PATCH v4 0/9] Create large folios in iomap buffered write path - Matthew Wilcox (Oracle)
- 2024-04-15 [PATCH v3 0/4] mm/filemap: optimize folio adding and splitting - Kairui Song
- 2024-05-21 Facing down mapcount madness [LWN.net]
- 2024-02-26 [PATCH v5 0/8] Split a folio to any lower order folios - Zi Yan
- 支持将 folio split 到任意 low order
- 2025-03-07 [PATCH v10 0/8] Buddy allocator like (or non-uniform) folio split - Zi Yan
- 支持 non-uniform folio split
- 2025-05-12 [PATCH v2 0/8] ext4: enable large folio for regular files - Zhang Yi
- 为 ext4 regular files 支持 large folio
- 2017-05-15 🚧 [PATCH -mm -v11 0/5] THP swap: Delay splitting THP during swapping out - Huang, Ying
selftest
- 2025-8-18[PATCH v5 0/5] Better split_huge_page_test result check 这一组patch增加了对于thp分裂后的order检查,Just note that the code does not handle memremapped THP, since it only checks page flags without checking the PFN. So when a vaddr range is mapped to a THP/mTHP head page and some other THP/mTHP tail pages, the code just treats the whole vaddr range as if it is mapped to a single THP/mTHP and gets a wrong order. After-split folios do not have this concern, so gather_after_split_folio_orders() is simplified to not handle such cases. 目前支持的场景如上,虽然baoling老师重用了这组patch在[RFC PATCH 00/11] add shmem mTHP collapse support但是可能有点仍会出现问题,目前ziyan老师局限的这种场景比较稳健
TAO
- 2024-02-29 🚧 [LSF/MM/BPF TOPIC] TAO: THP Allocator Optimizations - Yu Zhao
- 2024-05-24 Allocator optimizations for transparent huge pages [LWN.net]
- 2023-12-07 [PATCH v9 00/10] Multi-size THP for anonymous memory - Ryan Roberts
- 2024-09-20 Linux Plumbers Conference 2024: Product practices of large folios on millions of OPPO Android phones
- 2025-08-14 [RFC PATCH 0/7] add mTHP support for wp - Vernon Yang
- 2025-08-19 [PATCH v10 00/13] khugepaged: mTHP support - Nico Pache
- 2025-08-20 [RFC PATCH 00/11] add shmem mTHP collapse support - Baolin Wang
- An Empirical Evaluation of PTE Coalescing
- Every Mapping Counts in Large Amounts: Folio Accounting
selftests
selftests
-
2025-06-07 [PATCH v4] mm: use per_vma lock for MADV_DONTNEED - Barry Song
-
mm: madvise: use walk_page_range_vma() instead of walk_page_range()
-
do_madvise [behavior=MADV_DONTNEED]
-
madvise_lock
- lock_vma_under_rcu
- madvise_do_behavior
- madvise_single_locked_vma
- madvise_vma_behavior
- madvise_dontneed_free
- madvise_dontneed_single_vma
- map_page_range_single_batched [.reclaim_pt = true]
- unmap_single_vma
- unmap_page_range
- zap_p4d_range
- zap_pud_range
- zap_pmd_range
- zap_pte_range
- try_get_and_clear_pmd
- free_pte
- madvise_dontneed_free
- madvise_vma_behavior
- madvise_single_locked_vma
- madvise_do_behavior
调用关系如上所示 do_behavior 中遍历会调用 madvise_walk_vmas 就已经进行了 vma 的查找,之后调用 madvise_free_single_vma 时就不需要在 walk_page_range 进行 vma 的查找了,直接使用 use walk_page_range_vma()传入 vma 参数就可以,减少了一次 vma 的查找开销
- lock_vma_under_rcu
-
-
-
mm: use per_vma lock for MADV_DONTNEED 目前支持的 per vma 仅限于本地进程 single vma 同时不能涉及 uffd,这样的情况使用 rcu 机制可以极大的降低优先级翻转和读者等待,其他的情况回退到 mmap_lock(读写锁), 新的锁的模式 MADVISE_VMA_READ_LOCK 区别原来的读写锁只有 dontneed 和 free 这俩行为支持
-
mm: madvise: use per_vma lock for MADV_FREE 为 free 扩展 per vma 支持,同时之前的 walk page 的路径中增加 PGWALK_VMA_RDLOCK_VERIFY 只会锁住当前的 vma
-
mm: fix the race between collapse and PT_RECLAIM under per-vma lock collapse 合并时操作的是整个的 2M 空间的 vma,而之前的 dontneed 和 free 的逻辑在回收时候允许支持 per vma 造成了 lock race,通过改变 lock 顺序解除 lock race
-
- 2025-08-27 [PATCH v1 00/36] mm: remove nth_page()
- 2013-05-13 [PATCH 3/4] mm: Activate !PageLRU pages on mark_page_accessed if page is on local pagevec - Mel Gorman
- 2025-02-14 [PATCH v4 0/4] mm: batched unmap lazyfree large folios during reclamation - Barry Song
- 2025-04-02 [PATCH v2 8/9] mm: Remove swap_writepage() and shmem_writepage() - Matthew Wilcox (Oracle) 在 shrink_folio_list 时,只有 shmem 和 anon 会 pageout,脏文件页不会 pageout