内存管理-77-kernel-internals系列-Memory专题-Advanced-7-Maple Tree


一、Maple Tree: VMA Management Data Structure 翻译

注: 翻译自 https://kernel-internals.org/mm/maple-tree/

Maple Tree:VMA 管理数据结构

取代了 Linux 6.1 中用于虚拟内存区域(VMA)管理的 rbtree + 链表 的 B-tree 变体。


1. 关键源文件

-------------------------------------------------------------------------------------------------------------------------------------
文件                          用途
-------------------------------------------------------------------------------------------------------------------------------------
include/linux/maple_tree.h    公共 API:struct maple_tree、struct ma_state、所有宏和内联函数
lib/maple_tree.c              完整实现:maple_tree_init()、mas_walk()、mas_find()、mas_store()、mas_erase()
include/linux/mm_types.h      struct mm_struct 的嵌入(mm_mt)、struct vma_iterator、MM_MT_FLAGS
mm/mmap.c                     find_vma()、find_vma_intersection()、使用 __mt_destroy() 的进程地址空间销毁
mm/vma.c                      通过 vma_iter_store_gfp() 插入 VMA,通过 vma_iter_clear() 删除 VMA
kernel/fork.c                 mm_init():使用 mt_init_flags() 初始化 maple tree
-------------------------------------------------------------------------------------------------------------------------------------


2. 为什么 Maple Tree 取代了 rbtree + 链表

在 Linux 6.1 之前,每个 mm_struct 都为 VMA 维护了两套冗余的数据结构:

(1) 一棵以 vm_start 为键的红黑树(mm->mm_rb),提供按地址的 O(log n) 查找。
(2) 一条将所有 VMA 按地址顺序串起来的双向链表(vma->vm_next / vma->vm_prev),用于顺序遍历。

每次 VMA 的插入、删除或修改,都必须在 mmap_lock 保护下原子地更新这两个结构。除了代码复杂度之外,还有两个具体的性能代价:

(1) 顺序扫描时的缓存缺失。 遍历链表需要逐个跟随 vm_next 指针,每个指针可能指向不同 slab 对象中的不同缓存行。对于有数千个映射的进程,这会变成一长串追逐指针的访存。

(2) 内存开销。 每个 vm_area_struct 仅为索引就携带了三个 rbtree 节点字段(rb_node,以及嵌入在指针中的父指针和颜色)和两个链表指针,每个 VMA 约 40 字节。

Maple tree(在 v6.1 合入,由 Oracle 的 Liam Howlett 和 Matthew Wilcox 编写)将这两种结构统一为一种 B-tree 变体,原生支持按范围查找和高效的顺序遍历。因为 B-tree 节点将多个 pivot 和 slot 打包在一个 256 字节的缓存行中,一次节点访问就可以完成多次 pivot 比较,与 rbtree 中每次比较都要加载不同节点相比,大大减少了缓存缺失。


3. 什么是 Maple Tree

Maple tree 是一种支持 RCU 安全、按键范围索引的 B-tree。它存储互不重叠的 unsigned long 键范围,将每个范围映射到一个不透明指针。对于 VMA 管理,键是地址范围 [vm_start, vm_end - 1],值是 struct vm_area_struct * 。


3.1 节点类型和大小

定义了三种节点类型(来自 include/linux/maple_tree.h):

/* 64位上:每个节点256字节,按256字节对齐 */
#define MAPLE_NODE_SLOTS 31     /* 通用节点的 slot 数 */
#define MAPLE_RANGE64_SLOTS 16  /* range节点:15个pivot + 16个slot */
#define MAPLE_ARANGE64_SLOTS 10 /* alloc-range节点:9个pivot + 10个slot + gap */

实际使用的两种节点变体:

(1) maple_range_64 —— 标准的内部/叶子节点

struct maple_range_64 {
    struct maple_pnode *parent;
    unsigned long pivot[MAPLE_RANGE64_SLOTS - 1]; /* 15个范围边界 */
    union {
        void __rcu *slot[MAPLE_RANGE64_SLOTS]; /* 16个孩子或值指针 */
        struct {
            void __rcu *pad[MAPLE_RANGE64_SLOTS - 1];
            struct maple_metadata meta; /* 结束偏移 + 最大空洞 */
        };
    };
};

一个 maple_range_64 节点在 256 字节内存储最多 15 个 pivot 和 16 个 slot。用 B-tree 的术语说,pivot 是每个 slot 中存储范围的包含性上界。Slot i 覆盖范围 (pivot[i-1], pivot[i]],slot 0 从该节点的隐含最小值开始覆盖。

(2) maple_arange_64 —— 分配范围节点

struct maple_arange_64 {
    struct maple_pnode *parent;
    unsigned long pivot[MAPLE_ARANGE64_SLOTS - 1]; /* 9个范围边界 */
    void __rcu *slot[MAPLE_ARANGE64_SLOTS];        /* 10个指针 */
    unsigned long gap[MAPLE_ARANGE64_SLOTS];       /* 每个子树中最大的NULL空洞 */
    struct maple_metadata meta;
};

分配范围节点额外记录每个子树中连续 NULL 表项的最大空洞。这支持 mas_empty_area() / mas_empty_area_rev(),无需扫描整棵树就能找到给定大小的空闲地址范围——这对 mmap() 的地址选择至关重要。


3.2 节点分配

所有节点都从启动时由 maple_tree_init() 创建的名为 maple_node 的专用 kmem_cache 中分配:

void __init maple_tree_init(void)
{
    struct kmem_cache_args args = {
        .align = sizeof(struct maple_node),
        .sheaf_capacity = 32,
    };
    maple_node_cache = kmem_cache_create("maple_node", sizeof(struct maple_node), &args, SLAB_PANIC);
}

256 字节对齐保证节点指针的低 8 位恒为零。Maple tree 利用这些位直接在指针中编码节点类型和树的元数据,避免额外的内存访问。


3.3 树的最大高度

#define MAPLE_HEIGHT_MAX 31

每个 maple_range_64 节点有 16 个 slot,高度为 31 的树可以表示 16^31 个不同的范围——远远超过任何现实的地址空间。


4. struct maple_tree

/* include/linux/maple_tree.h */
struct maple_tree {
    union {
        spinlock_t ma_lock;
#ifdef CONFIG_LOCKDEP
        struct lockdep_map *ma_external_lock;
#endif
    };
    unsigned int ma_flags;
    void __rcu *ma_root;
};

ma_lock —— 内部自旋锁,在没有提供外部锁时使用。对于 mm->mm_mt 未使用:该树配置了 MT_FLAGS_LOCK_EXTERN,由 mmap_lock 作为串行化锁。
ma_flags —— 树全局属性的位掩码(见下文)。
ma_root —— 受 RCU 保护的根节点指针(如果树在索引 0 处恰好只有一个表项,则为单个存储值)。


4.1 标志

#define MT_FLAGS_ALLOC_RANGE 0x01  /* 跟踪每个节点的最大空闲空洞 */
#define MT_FLAGS_USE_RCU     0x02  /* 节点通过RCU释放 */
#define MT_FLAGS_LOCK_IRQ    0x100 /* ma_lock以IRQ安全方式获取 */
#define MT_FLAGS_LOCK_BH     0x200 /* ma_lock以BH安全方式获取 */
#define MT_FLAGS_LOCK_EXTERN 0x300 /* 外部锁;ma_lock未使用 */


4.2 mm_struct 如何嵌入 maple tree

/* include/linux/mm_types.h */
struct mm_struct {
    ...
    struct maple_tree mm_mt;
    ...
    struct rw_semaphore mmap_lock;
    ...
};

/* 初始化 mm->mm_mt 时使用的标志 */
#define MM_MT_FLAGS (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | MT_FLAGS_USE_RCU)

mm->mm_mt 同时启用了这三个标志:

MT_FLAGS_ALLOC_RANGE —— 启用空洞跟踪,使 mmap() 能高效找到空闲区域。
MT_FLAGS_LOCK_EXTERN —— 绕过树的内部 ma_lock 自旋锁;调用者在任何修改前必须持有 mmap_lock 写锁。
MT_FLAGS_USE_RCU —— 被删除的节点通过 call_rcu() 而不是立即释放,从而支持无锁的 RCU 读者(见下文 [RCU 安全])。

该树在 mm_init()(kernel/fork.c)中初始化并绑定到 mmap_lock:

static struct mm_struct *mm_init(struct mm_struct *mm, ...) {
    mt_init_flags(&mm->mm_mt, MM_MT_FLAGS);
    mt_set_external_lock(&mm->mm_mt, &mm->mmap_lock);
    ...
}


5. RCU 安全

Maple tree 通过确保从树中移除的节点,在所有当前正在执行的 RCU 读端临界区完成后才被释放,从而实现无锁读。当设置了 MT_FLAGS_USE_RCU 时,删除路径会调用 call_rcu() 而不是立即释放:

/* lib/maple_tree.c —— 节点删除路径 */
if (mt_in_rcu(mt)) {
    mt_destroy_walk(enode, mt, false);
    call_rcu(&node->rcu, mt_free_walk); /* 延迟释放 */
} else {
    mt_destroy_walk(enode, mt, true);   /* 立即释放 */
}

struct maple_node 在节点从树中摘除后,将其 slot[] 数组复用为 rcu_head(两者存在于 union 中)。在节点被摘除前从 slots[] 加载了指针的读者可以安全地继续解引用它;该内存在其 RCU 宽限期结束前不会归还给分配器。


5.1 mm 中 RCU 模式的生命周期

mm->mm_mt 大多数时间以启用 RCU 的模式运行。在进程销毁和 dup_mmap() 路径中,内核会临时禁用 RCU 模式,以避免在批量丢弃节点时延迟释放的开销:

/* mm/mmap.c —— exit_mmap() */
mt_clear_in_rcu(&mm->mm_mt); /* 销毁时切换为立即释放 */
...
__mt_destroy(&mm->mm_mt); /* 释放所有剩余节点 */

/* mm/mmap.c —— dup_mmap() —— 批量复制完成后 */
mt_set_in_rcu(vmi.mas.tree); /* 在新的mm上重新启用RCU */

mt_set_in_rcu() 和 mt_clear_in_rcu() 在树的锁保护下开关 MT_FLAGS_USE_RCU。


5.2 无锁 VMA 查找(per-VMA 锁快路径)

仅持有 rcu_read_lock() 而不持有 mmap_lock 的读者,可以安全地遍历 mm->mm_mt 来查找 VMA。这是 per-VMA lock 快速路径的基础:

/* mm/mmap_lock.c —— lock_vma_under_rcu() */
MA_STATE(mas, &mm->mm_mt, address, address);

rcu_read_lock();
vma = mas_walk(&mas); /* 在RCU下无锁遍历maple tree */
if (!vma)
    goto inval;
vma = vma_start_read(mm, vma); /* 尝试获取per-VMA读锁 */
...
rcu_read_unlock();

mas_walk() 仅通过读取 __rcu 注解的指针和 pivot,从根走到叶子。不需要加锁,因为被删除的节点在至少一个 RCU 宽限期内仍然有效。


6. MA_STATE 和 Maple State 游标

struct ma_state 是所有高级 maple tree API 的操作游标。它跟踪树中的当前位置,使顺序操作(例如遍历所有 VMA)无需每次都从根重新开始。

/* include/linux/maple_tree.h */
struct ma_state {
    struct maple_tree *tree;  /* 正在操作的树 */
    unsigned long index;      /* 当前操作的范围起点 */
    unsigned long last;       /* 当前操作的范围终点 */
    struct maple_enode *node; /* 当前节点 */
    unsigned long min;        /* 当前节点的隐含最小值 */
    unsigned long max;        /* 当前节点的隐含最大值 */
    struct slab_sheaf *sheaf; /* 预分配的节点池 */
    struct maple_node *alloc; /* 单个预分配节点(快路径) */
    unsigned long node_request; /* 预分配的节点数 */
    enum maple_status status;   /* ma_start / ma_active / ma_none / ma_error / ... */
    unsigned char depth;        /* 写路径下潜时的深度 */
    unsigned char offset;       /* 当前节点内的slot/pivot索引 */
    unsigned char mas_flags;
    unsigned char end;          /* 当前节点中最后使用的slot */
    enum store_type store_type; /* 需要的写类型 */
};

status 字段决定下一次操作如何对待游标:注: 6.1.115内核上还没有这个 status 字段。

-------------------------------------------------------------------------------------------------------------------------------------
状态            含义
-------------------------------------------------------------------------------------------------------------------------------------
ma_start        尚未定位;下一次操作从根开始遍历
ma_active       游标在 node / offset 处有效;可安全原地继续
ma_none         搜索完成;在 index 处未找到表项
ma_root         在根指针中找到表项(树只有一个表项)
ma_pause        节点数据可能已过期;需要重启(例如锁曾被释放)
ma_overflow     到达搜索上限
ma_underflow    到达搜索下限
ma_error        发生错误;node 编码了负的 errno
-------------------------------------------------------------------------------------------------------------------------------------

MA_STATE 宏在栈上初始化游标:

#define MA_STATE(name, mt, first, end) \
    struct ma_state name = { \
        .tree = mt, \
        .index = first, \
        .last = end, \
        .node = NULL, \
        .status = ma_start, \
        .min = 0, \
        .max = ULONG_MAX, \
        ... \
    }

操作完成后,mas->index 和 mas->last 保存找到或存储的表项的完整范围。在 mm/mmap.c 和 mm/vma.c 中广泛使用的 struct vma_iterator 是一个薄封装:

/* include/linux/mm_types.h */
struct vma_iterator {
    struct ma_state mas;
};

#define VMA_ITERATOR(name, __mm, __addr) \
    struct vma_iterator name = { \
        .mas = { \
            .tree = &(__mm)->mm_mt, \
            .index = __addr, \
            .status = ma_start, \
        }, \
    }


7. 关键操作

7.1 树生命周期:mt_init() 和 mtree_destroy()

/* 以默认标志初始化空树(无外部锁,无RCU) */
static inline void mt_init(struct maple_tree *mt) {
    mt_init_flags(mt, 0);
}

/* 以指定标志初始化(用于 mm->mm_mt) */
static inline void mt_init_flags(struct maple_tree *mt, unsigned int flags);

/* 销毁树并释放所有节点(内部获取 ma_lock) */
void mtree_destroy(struct maple_tree *mt);

/* 无锁销毁——调用者必须持有外部锁 */
void __mt_destroy(struct maple_tree *mt);

对于 mm->mm_mt,mm_init() 使用 MM_MT_FLAGS 调用 mt_init_flags()。在 exit_mmap() 和 dup_mmap() 错误路径中的销毁,使用 __mt_destroy(&mm->mm_mt),此时调用者已持有 mmap_lock 写锁。


7.2 mas_walk() —— 将游标定位到 index

void *mas_walk(struct ma_state *mas);

在树中搜索 mas->index。返回时,mas->index 和 mas->last 被设置为找到的表项的范围(如果没找到,则为 0 和 ULONG_MAX)。不会推进游标;在同一 index 上调用两次 mas_walk() 返回同一表项。

可以仅在 rcu_read_lock() 下安全调用(无需写锁)。per-VMA 锁快路径直接使用它:

MA_STATE(mas, &mm->mm_mt, address, address);
rcu_read_lock();
vma = mas_walk(&mas);


7.3 mas_find() —— 从 index 向前迭代

void *mas_find(struct ma_state *mas, unsigned long max);

返回范围与 [mas->index, max] 重叠的下一个表项。成功返回后,mas->index 和 mas->last 描述返回表项的范围,游标定位于此;下一次调用从 mas->last + 1 开始向前扫描。当剩余范围内没有表项时返回 NULL(状态设为 ma_overflow)。必须在持有 rcu_read_lock() 或写锁时调用。

mas_for_each() 宏使用它:

#define mas_for_each(__mas, __entry, __max) \
    while (((__entry) = mas_find((__mas), (__max))) != NULL)


7.4 mas_store() / mas_store_gfp() —— 插入或更新范围映射

/* 在 [mas->index, mas->last] 存储entry。需要预分配节点。 */
void *mas_store(struct ma_state *mas, void *entry);

/* 按需分配的存储(失败返回 -ENOMEM)。 */
int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp);

两个函数都将 entry 写入 [mas->index, mas->last] 范围,调用前必须设置好该范围。如果已有表项与该范围重叠,会被挤出(按需分割、收缩或替换)。mas_store() 返回第一个被挤出的表项(如果有);mas_store_gfp() 返回 0 或 -ENOMEM。

需要写锁。

在 VMA 代码中,vma_iter_store_gfp() 封装了 mas_store_gfp():

/* mm/vma.h */
static inline int vma_iter_store_gfp(struct vma_iterator *vmi, struct vm_area_struct *vma, gfp_t gfp)
{
    __mas_set_range(&vmi->mas, vma->vm_start, vma->vm_end - 1);
    mas_store_gfp(&vmi->mas, vma, gfp);
    if (unlikely(mas_is_err(&vmi->mas)))
        return -ENOMEM;
    vma_mark_attached(vma);
    return 0;
}


7.5 mas_erase() —— 删除当前位置的表项

void *mas_erase(struct ma_state *mas);

找到包含 mas->index 的范围,擦除整个范围(存入 NULL),并返回之前的表项。返回时,mas->index 和 mas->last 被设置为被擦除的范围。

需要写锁。

在 VMA 代码中,删除路径使用 vma_iter_clear(),它以 NULL 调用 mas_store_prealloc():

/* mm/vma.h */
static inline void vma_iter_clear(struct vma_iterator *vmi) {
    mas_store_prealloc(&vmi->mas, NULL);
}


7.6 mt_for_each() —— 简单的全树遍历

/* include/linux/maple_tree.h */
#define mt_for_each(__tree, __entry, __index, __max) \
    for (__entry = mt_find(__tree, &(__index), __max); \
         __entry; \
         __entry = mt_find_after(__tree, &(__index), __max))

mt_for_each 使用更简单的 mt_find() / mt_find_after() 接口(每次调用内部获取并释放 rcu_read_lock()),而不是显式的 ma_state。适合不需要在迭代之间维护游标状态的只读遍历。


8. 代码示例

8.1 按地址查找 VMA

/* find_vma() —— mm/mmap.c */
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
    unsigned long index = addr;
    mmap_assert_locked(mm);
    return mt_find(&mm->mm_mt, &index, ULONG_MAX);
}

mt_find() 从 index 开始,返回覆盖 addr 或紧随其后的第一个表项。对于地址查找,这等价于问“哪个 VMA 覆盖 addr,如果没有,下一个是哪个”。


8.2 mmap 期间插入 VMA

/* mm/vma.c —— 匿名映射创建(简化) */
vma = vm_area_alloc(mm);
vma_set_range(vma, addr, addr + len, pgoff);
vm_flags_init(vma, vm_flags);
vma_start_write(vma); /* 标记VMA为写锁定 */

if (vma_iter_store_gfp(vmi, vma, GFP_KERNEL))
    goto mas_store_fail;
mm->map_count++;


8.3 遍历所有 VMA(例如用于 /proc/PID/maps)

VMA_ITERATOR(vmi, mm, 0);
struct vm_area_struct *vma;
for_each_vma(vmi, vma) {
    /* vma->vm_start, vma->vm_end, vma->vm_flags ... */
}

for_each_vma 基于 vma_next(),它让 vma_iterator 在 maple tree 中向前推进,而无需从根重新开始。


8.4 查找空闲地址范围(mmap 提示搜索)

/* mas_empty_area() —— 在 [min, max] 中找至少 size 字节的空洞 */
MA_STATE(mas, &mm->mm_mt, 0, 0);
mas_empty_area(&mas, mmap_min_addr, mmap_end - len, len);
addr = mas.index;

这利用 maple_arange_64 节点中的 gap[] 数组跳过不可能包含足够大空洞的子树,使空闲范围搜索为 O(log n) 而不是 O(n)。


9. 与 rbtree 的性能对比

-------------------------------------------------------------------------------------------------------------------------------------
属性                           rbtree + 链表                     Maple tree
-------------------------------------------------------------------------------------------------------------------------------------
点查找                         O(log n)                          O(log n)
顺序扫描                       O(n) 指针追逐                      O(n) 顺序节点读取
空闲空洞搜索                    O(n) 全扫描                       O(log n),通过 gap 元数据
每节点缓存行                    1(每个节点一个 VMA 指针)           每个 256 字节节点最多 16 个表项
每个 VMA 的内存(索引开销)       ~40 字节(rb_node + 链表指针)      摊销 ~16 字节(共享节点)
读锁                           需要 mmap_lock                    RCU 读锁即可
更新复杂度                      更新两个结构                       更新一棵树
-------------------------------------------------------------------------------------------------------------------------------------

对于顺序扫描(例如读取 /proc/PID/maps 或对大范围 mprotect()),关键优势在于一个 maple_range_64 节点在一个 256 字节分配中容纳 16 个 VMA 指针。遍历一个满节点只需一次缓存缺失加载节点,然后得到最多 16 个有效表项,而跟随链表时每个表项需要一次cache-miss。对于有数千个映射的地址空间(JVM、大型应用、容器运行时),这种缓存压力的降低是可测量的。


10. 调试

10.1 /proc/PID/maps 和 /proc/PID/smaps

这些文件通过直接遍历 mm->mm_mt 生成。读取它们无需任何改动;maple tree 是权威来源。


10.2 CONFIG_DEBUG_MAPLE_TREE

通过 lib/Kconfig.debug 启用:

CONFIG_DEBUG_MAPLE_TREE=y # 需要 CONFIG_DEBUG_KERNEL=y

启用后:

(1) MT_BUG_ON()、MAS_BUG_ON() 和 MT_WARN_ON() 在每次树操作时执行额外的一致性检查,失败时转储整棵树。
(2) 在每次写入前,mas_store() 内部执行额外的范围校验。
(3) 可以显式调用 mt_validate() 检查任何树的结构完整性:

void mt_validate(struct maple_tree *mt);

mt_validate() 检查所有 pivot 数组是否有序、没有范围重叠、gap 元数据一致,以及 ma_flags 中存储的高度与实际树深是否匹配。


10.3 mt_dump()

void mt_dump(const struct maple_tree *mt, enum mt_dump_format format);

以十进制(mt_dump_dec)或十六进制(mt_dump_hex)格式将整棵树打印到内核日志。仅在 CONFIG_DEBUG_MAPLE_TREE=y 时可用。MT_BUG_ON() 和 MAS_BUG_ON() 失败时会自动调用。


10.4 mas_dump()

void mas_dump(const struct ma_state *mas);

打印 ma_state 游标的当前状态(index、last、节点指针、status、min/max、depth、offset)。

用于调试不正确的游标状态时很有用。


10.4 跟踪 maple tree 操作

Maple tree 有内置 tracepoint(trace_ma_read、trace_ma_write、trace_ma_op),分布在 lib/maple_tree.c 中。当相应的 maple_tree 事件组启用时,可通过 ftrace 查看,无需 CONFIG_DEBUG_MAPLE_TREE 即可对每次树操作提供可见性。


10.5 RCU 模式与调试

当 CONFIG_DEBUG_MAPLE_TREE 与 CONFIG_MAPLE_RCU_DISABLED(lib/maple_tree.c 顶部的编译时选项)结合时,RCU 释放被完全抑制,节点被立即释放。这有助于暴露树使用者的 use-after-free bug,但不适合生产环境。


11. 与其他子系统的关系

(1) Per-VMA 锁(mm/mmap_lock.c)依赖 MT_FLAGS_USE_RCU 在 rcu_read_lock() 下执行无锁 VMA 查找。

(2) /proc/PID/maps 在持有 mmap_lock 读锁时,通过 for_each_vma() 遍历 mm->mm_mt。

(3) dup_mmap() 使用 __mt_dup() 将父进程 maple tree 批量复制到子进程 mm,然后用 vma_iter_clear_gfp() 替换 VM_DONTCOPY 表项。

(4) execve() 通过调用 exit_mmap() 销毁地址空间,exit_mmap() 在清除所有页表项后调用 __mt_destroy(&mm->mm_mt)。

(5) vmalloc 使用红黑树(free_vmap_area_root,struct rb_root)跟踪内核虚拟地址空间——不是 maple tree。


12. 延伸阅读

LWN:The maple tree, a modern data structure for a complex problem —— 由 Liam Howlett 和 Matthew Wilcox 于 2022 年撰写的文章,解释了设计原理、节点布局,以及与 rbtree + 链表组合对比的基准测试结果。
lib/maple_tree.c —— 完整实现:maple_tree_init()、mas_walk()、mas_find()、mas_store()、mas_erase()、通过 mt_free_walk() 实现的 RCU 节点释放,以及 CONFIG_MAPLE_RCU_DISABLED 调试模式。
include/linux/maple_tree.h —— 公共 API:struct maple_tree、struct ma_state、MA_STATE()、mt_for_each()、节点类型常量以及所有标志定义。
提交 54a611b60590 —— 在 Linux 6.1 中合入 maple tree、取代 mm->mm_rb 和 VMA 链表的提交;合并信息中链接了完整的补丁系列和基准测试结果。
per-vma-locks.md —— per-VMA 锁快路径,依赖 MT_FLAGS_USE_RCU,在不持有 mmap_lock 的情况下,在 rcu_read_lock() 下执行无锁的 maple tree 遍历。
LWN:Splitting VMAs —— 介绍了 Linux 6.7 中的 VMA 树重组工作,该工作得益于更简洁的 maple tree API,将 VMA 操作辅助函数移入了 mm/vma.c。

 

posted on 2026-10-08 10:45  Hello-World3  阅读(3)  评论(0)    收藏  举报

导航