透明大页mapcount和refcount
之前我们在mapcount中研究过Folio的mapcount变化情况,但是当时我们并没有具体的例子。
现在我们结合thp的分配/拆分/合并,来展开看看mapcount在这些过程中是如何变化的。
与此同时,folio中的refcount和mapcount还有一定的关系。比如在folio_expected_ref_count()中,其中就考虑到了两者的关系。
static inline int folio_expected_ref_count(const struct folio *folio)
{
const int order = folio_order(folio);
int ref_count = 0;
...
/* One reference per page table mapping. */
return ref_count + folio_mapcount(folio);
}我们只看最后一行的注释,这说明只要folio在页表中被映射一条,那就会拿到一个refcount。
所以事实是不是如此呢?
THP 分配
do_huge_pmd_anonymous_page -> __do_huge_pmd_anonymous_page
vma_alloc_anon_folio_pmd() -> vma_alloc_folio()
folio_alloc_noprof() -> __folio_alloc_noprof()
set_page_refcounted(page) // refcount = 1
map_anon_folio_pmd_pf() -> map_anon_folio_pmd_nopf()
folio_add_new_anon_rmap(folio, vma, addr, RMAP_EXCLUSIVE)设置后的结果:
_entire_mapcount: 1
_large_mapcount: 1
_nr_pages_mapped: ENTIRELY_MAPPED
_refcount: 1此时我们可以看到 _refcount == _large_mapcount,这个是符合预期的。
mTHP 分配
do_anonymous_page
alloc_anon_folio() -> vma_alloc_folio()
folio_alloc_noprof() -> __folio_alloc_noprof()
set_page_refcounted(page) // refcount = 1
folio_ref_add(folio, nr_pages - 1)
folio_add_new_anon_rmap(folio, vma, addr, RMAP_EXCLUSIVE)设置后的结果:
_mapcount: 1
_large_mapcount: nr_pages
_nr_pages_mapped: nr_pages
_refcount: nr_pages一开始我有个疑问,为什么这种情况下_large_mapcount还要加nr_pages,直接加1不好么?
后来想想是有道理的。
从语义上讲,一个_large_mapcount计数代表了有多少个PTE/PMD映射了这个folio
从代码上看,其中要求一个mapcount对应一个refcount
所以这个时候也是符合预期的, _refcount == _large_mapcount。
THP 拆分
在THP split中,我们学习了一下大页拆分的过程。
其中涉及到mapcount的有两个地方:
unmap_folio()
remap_page()
按照目前的理解,unmap_folio()执行后,folio中mapcount有关的计数应当都清零了。
unmap_folio
这个执行的流程在:
try_to_migrate_one
split_huge_pmd_locked
folio_remove_rmap_pmd
__folio_remove_rmap(, PGTABLE_LEVEL_PMD)
设置的变动如下: (-1表示原值-1)
_entire_mapcount: -1
_large_mapcount: -1
_nr_pages_mapped: -ENTIRELY_MAPPED这么看,这样正好和之前分配大页时的操作对应。把分配时设置的mapcount都清除了。
remap_folio
这个执行的流程在:
remove_migration_pte
folio_add_anon_rmap_pte
__folio_add_anon_rmap(, PGTABLE_LEVEL_PTE)这时候就按照单独的folio来计数了。
THP 合并
Last updated
Was this helpful?