You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何维护映射为非透明大页的Linux folio的rmap及相关实现疑问

关于Linux 6.0中struct folio与rmap的疑问

概述

Linux 6.0版本中,struct folio的文档指出:

它可以被映射到用户空间的任意页偏移地址……

但实际使用中发现,似乎只有当folio用作透明大页(THP)时,才能正确维护其页面的rmap——这要求用户空间地址也对齐到THP大小。那么对于非THP用途的folio,是否存在正确维护rmap的方法?

详细说明

folio是一组物理、虚拟和逻辑上连续的字节,大小为2的幂(来自内核文档)。struct folio是复合页的头页。folio的设计初衷是区分针对复合页头页的API和针对普通页的API,大页是其典型应用场景之一。

举个例子:一个order为2的folio,包含物理页pfn、pfn+1、pfn+2、pfn+3,其物理地址和内核虚拟地址都会对齐到4页边界(pfn & 0x3 == 0)。

根据文档描述,内核允许将folio映射到未对齐的用户空间虚拟地址(比如vpn、vpn+1、vpn+2、vpn+3,其中vfn & 0x3 != 0),这说明folio并非仅用于THP。我的使用场景中,该folio不是THP,也不符合2MB或1GB大页的order要求,但映射时需要正确维护rmap。

然而当前的rmap代码似乎仅支持THP用途的folio,例如page_add_new_anon_rmap函数中的代码片段:

void page_add_new_anon_rmap(struct page *page,
    struct vm_area_struct *vma, unsigned long address)
{
    const bool compound = PageCompound(page);
    int nr = compound ? thp_nr_pages(page) : 1;

    if (compound) {
        VM_BUG_ON_PAGE(!PageTransHuge(page), page);
        ....
    }
}

问题

  1. 当前Linux的folio和rmap实现是否仅针对THP?
  2. 是否存在一种“正确”的方式来映射非THP用途的folio同时维护rmap?

回答

问题1:folio和rmap实现是否仅针对THP?

不是。struct folio的设计目标是统一处理所有复合页场景,THP只是其中一个典型应用。早期基于struct page的复合页API存在接口模糊的问题,folio的引入就是为了明确区分“复合页头页”与“普通页”的操作逻辑,覆盖的场景包括但不限于:

  • 透明大页(THP)
  • 块设备的bio聚合页
  • 文件系统的多页缓存(如XFS的大页缓存)
  • 自定义复合页使用场景

但rmap子系统的部分API确实与THP强绑定,比如你提到的page_add_new_anon_rmap——这个函数本身就是为匿名THP设计的,因此会强制检查PageTransHuge标记。普通复合页(非THP)需要使用通用复合页rmap接口,而非THP专属函数。

问题2:如何正确映射非THP的folio并维护rmap?

针对非THP的folio,需避开THP专属rmap API,改用通用复合页或folio专属接口,具体操作如下:

  1. 区分匿名页与文件页场景

    • 匿名folio:不要使用page_add_new_anon_rmap,可直接调用folio_add_anon_rmap(Linux 6.0+提供的folio专属API),该函数会自动遍历folio的所有子页并添加rmap条目;也可以手动遍历每个子页,分别调用page_add_new_anon_rmap。
    • 文件页folio:使用folio_add_file_rmap或针对子页调用page_add_file_rmap,根据映射需求选择。
  2. 确保folio标记正确

    • 非THP的folio不要设置PageTransHuge标记,避免触发THP相关的rmap校验逻辑。
    • 确保folio_order等元数据正确配置,让rmap子系统能识别folio的大小。
  3. 地址映射的处理
    即使用户空间地址未对齐,只要为folio的每个子页正确关联对应的用户虚拟地址,rmap就能正常工作。比如order=2的folio映射到vpn起始地址时,需为vpn、vpn+1、vpn+2、vpn+3四个虚拟地址分别对应folio的四个子页完成rmap关联(使用folio_add_anon_rmap可自动完成此过程)。

  4. 优先使用folio专属rmap API
    Linux 6.0及以后版本提供了一批专为folio设计的rmap函数,无需手动处理子页,同时规避THP限制:

    • folio_add_anon_rmap:为匿名folio添加rmap
    • folio_add_file_rmap:为文件页folio添加rmap
    • folio_remove_rmap:移除folio的rmap

示例代码(匿名folio场景):

struct folio *folio = folio_alloc_order(GFP_KERNEL, 2);
// 假设已将folio映射到用户空间vpn起始地址
folio_add_anon_rmap(folio, vma, vpn);

需要注意的是,非THP的folio在rmap中会被当作多个独立页处理,每个子页的rmap条目单独维护——这与THP将整个folio作为单个大页维护rmap的逻辑不同,但这是符合非THP场景的预期行为。


内容的提问来源于stack exchange,提问作者TSG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 18:50:29