[TOC]
历史与背景 这项技术是为了解决什么特定问题而诞生的? Maple Tree(枫树)是为了解决Linux内核内存管理子系统中的一个核心性能瓶颈而设计的。具体来说,它是为了取代管理虚拟内存区域(Virtual Memory Areas, VMAs)的红黑树(Red-Black Tree) 。
在Maple Tree出现之前,每个进程的内存地址空间(struct mm_struct
)都使用一棵红黑树来组织其所有的VMA。当进程的VMA数量非常多时(例如大型数据库或科学计算应用),以及在多线程环境下,这棵红-黑树成为了一个严重的争用点:
锁争用(Lock Contention) :对VMA树的任何修改(如mmap
, munmap
)都需要获取一个重量级的读写信号量(mmap_sem
,现在是mmap_lock
)。在写者持有锁期间,所有其他试图查找或修改VMA的线程都会被阻塞,这严重限制了内存密集型应用的可扩展性。
缓存效率低下(Cache Inefficiency) :红黑树是一种指针密集型的数据结构。树的每个节点都是一个单独的、小的内存分配。遍历树的过程涉及到在内存中进行大量的指针“跳跃”,这会导致很差的CPU缓存局部性(cache locality),从而频繁地从主内存加载数据,拖慢查找速度。
范围操作复杂 :虽然红黑树可以进行范围查找,但其实现和性能并非最优。
Maple Tree被设计为一种在现代多核CPU上表现更佳的数据结构,专门优化以解决以上所有问题。
它的发展经历了哪些重要的里程碑或版本迭代? Maple Tree是由内核开发者Liam R. Howlett主导设计和实现的。
构思与开发 :该项目旨在创建一个专为VMA管理优化的、兼顾高性能和高并发性的数据结构。
正式引入 :Maple Tree在Linux 5.14内核版本中首次被引入,并开始逐步替换内存管理中的红黑树。这是一个重要的里程碑,标志着内核核心数据结构的现代化演进。
成为VMA默认 :经过几个内核版本的迭代和稳定,Maple Tree最终成为了管理VMA的默认数据结构,完全取代了原来的红黑树实现。
通用化 :除了VMA,Maple Tree也被设计成一个通用的库(lib/maple_tree.c
),可供内核其他需要高性能范围映射的子系统使用。
目前该技术的社区活跃度和主流应用情况如何? Maple Tree是当前Linux内核内存管理子系统中一个非常核心和活跃的组件。
核心应用 :它是所有现代Linux内核管理进程虚拟地址空间的标准方式。
持续优化 :社区和主要作者仍在不断对其进行性能优化和功能增强。
逐步推广 :由于其优越的性能,其他内核子系统也开始考虑或已经在使用Maple Tree来管理地址范围或其他类型的范围数据。
核心原理与设计 它的核心工作原理是什么? Maple Tree是一种缓存优化的B树(Cache-conscious B-Tree)变体,专门用于存储和查询 非重叠的范围(non-overlapping ranges) 。
B树结构 :与每个节点只有一个数据项的二叉树(如红黑树)不同,B树的每个节点内部都是一个数组(称为“槽位”,slots)。这使得每个节点可以存储多个范围的分界点(pivots)和指向子节点的指针(或在叶子节点中直接存储数据)。
缓存友好 :将多个指针或数据项紧凑地存储在一个节点数组中,极大地提高了CPU缓存的利用率。当CPU加载一个节点到缓存时,它一次性获取了大量相关信息,后续的查找操作可以在缓存中快速完成,减少了对主内存的访问。
为范围而生 :它的节点设计天然适合范围操作。一个节点内的多个分界点可以快速地将一个大的范围划分成多个子范围,引导查找操作高效地进入对应的子树。
读-拷贝-更新(RCU)友好 :这是Maple Tree最重要的设计之一。
无锁读取 :对Maple Tree的查找和遍历操作是无锁 的。它们在RCU的保护下进行,不会被写操作阻塞。这是对红黑树mmap_lock
巨大瓶颈的根本性改进。
写操作 :当需要修改树时(插入或删除一个VMA),写者会复制从根节点到目标叶子节点路径上的所有节点(这就是“拷贝”)。然后在新复制的节点上进行修改,最后通过一次原子的指针交换操作,将树的根指向新的、修改后的路径。旧的路径会在所有读者都离开后被RCU机制安全地回收。这个过程虽然对写者来说更复杂,但它保证了读者可以一直无锁地、安全地访问树的一个稳定快照。
它的主要优势体现在哪些方面?
极高的并发性 :通过RCU实现的无锁读取,极大地提高了多线程应用在内存操作上的可扩展性。
卓越的缓存性能 :B树的节点结构显著减少了指针追逐,提高了缓存命中率,从而加速了查找操作。
高效的范围操作 :其数据结构天然适合快速定位和遍历一个地址范围内的所有VMA。
写操作锁粒度优化 :虽然写操作仍需同步,但其锁定机制比旧的mmap_lock
更精细,且不会阻塞读者。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
实现复杂 :RCU和写时复制的更新机制使得Maple Tree的内部实现比红黑树复杂得多,理解和调试的门槛更高。
写操作开销 :对于写操作,需要复制路径上的多个节点,这在理论上比红黑树的“原地”旋转和重新着色有更高的开销。但在高并发场景下,这种开销被无锁读取带来的巨大收益所弥补。
不适合单值查找 :虽然可以做到,但如果需求仅仅是单个键到值的映射(非范围),那么哈希表通常是更简单、更高效的选择。
使用场景 在哪些具体的业务或技术场景下,它是首選解決方案?請舉例說明。 在内核中,任何需要管理大量非重叠范围,并且对并发读性能有极高要求 的场景,Maple Tree都是首选解决方案。
虚拟内存区域(VMA)管理 :这是其设计的初衷和最核心的应用。当一个进程访问一个内存地址时,内核需要快速地从数千甚至数万个VMA中找到包含该地址的VMA。在多线程环境下,多个线程可能同时在进行这种查找,Maple Tree的无锁读取特性完美地满足了这一需求。
其他潜在应用 :
高级中断管理 :管理中断号范围到处理程序的映射。
设备内存映射 :管理物理设备地址范围到驱动程序的映射。
文件系统范围锁 :管理文件内字节范围的锁。
是否有不推荐使用该技术的场景?为什么?
简单的键值对映射 :如果你的键没有范围的概念(例如,通过PID查找进程),哈希表是更好的选择,因为它平均查找时间是O(1)。
需要严格有序遍历且并发度不高 :如果主要操作是按键排序遍历,且写操作不频繁、并发度低,那么红黑树因为实现更简单,可能是一个更易于维护的选择。
数据量非常小 :对于少量的数据,使用简单的数据结构如链表可能就足够了,引入Maple Tree的复杂性得不偿shī。
对比分析 请将其 与 其他相似技术 进行详细对比。
特性
Maple Tree
红黑树 (Red-Black Tree)
哈希表 (Hash Table)
基数树/XArray
核心功能
并发的、缓存优化的范围映射
有序的单键映射
无序的单键映射
针对整数/指针键的、空间优化的有序映射
数据模型
范围 到 值
单个键 到 值
单个键 到 值
整数索引 到 值
并发/锁
RCU保护,读取无锁
需读写锁或自旋锁保护
需锁保护(通常是分桶锁)
RCU保护,读取通常无锁
缓存效率
高 (节点内是数组)
低 (指针密集,追逐指针)
高 (数组访问)
高 (Trie结构,路径压缩)
查找性能
O(log N) - 但常数因子小,缓存友好
O(log N) - 但常数因子大,缓存不友好
平均 O(1)
O(k) (k为索引位数)
范围查找
非常高效
支持,但效率不如B树
不支持
支持,效率高
实现复杂性
非常高
中等
较低
高
典型用途
VMA管理 ,高性能范围锁
定时器管理,文件描述符管理
dcache,PID表,连接跟踪
页缓存 ,文件描述符表
maple_tree
和 Radix Tree
的区别、相似点以及各自的应用场景。maple_tree
和 Radix Tree
是 Linux 内核中两种高效的树形数据结构,它们各自有不同的设计目标、实现方式和应用场景。以下是两者的区别、相似点以及各自的应用场景。
1. 设计目标 1.1 maple_tree
目标 : 提供高效的范围操作、低内存占用以及并发友好性。
特点 :
支持范围(range)存储,适合稀疏或连续数据的管理。
通过多叉树结构减少树的高度,提升查找效率。
使用 RCU(Read-Copy-Update)机制支持无锁读操作,适合高并发场景。
1.2 Radix Tree
目标 : 高效管理稀疏数据,提供快速的查找、插入和删除操作。
特点 :
基于压缩前缀树(Compressed Prefix Tree),通过共享公共前缀节省内存。
适合存储稀疏数据,例如文件系统页缓存或 ID 分配。
主要用于单值存储,而不是范围操作。
2. 实现方式 2.1 数据结构 maple_tree
多叉树结构 : 每个节点可以存储多个键值对或范围,减少树的高度。
节点类型 :
稠密节点(dense nodes): 存储连续的索引值。
范围节点(range nodes): 存储范围数据。
叶子节点和内部节点明确分开。
Radix Tree
压缩前缀树 : 通过共享前缀减少存储空间。
节点结构 :
每个节点表示路径中的一部分。
支持路径压缩,减少树的深度。
2.2 并发支持 maple_tree
RCU 支持 : 读操作无锁,写操作延迟生效,适合高并发环境。
写操作锁 : 使用 spinlock
确保写操作的安全性。
Radix Tree
RCU 支持 : 允许无锁读操作。
写操作 : 传统写操作需要加锁,部分操作可能没有 maple_tree
那么高效。
2.3 范围操作支持 maple_tree
原生支持范围存储和操作,例如范围插入、范围删除等。
适合管理连续的或稀疏的范围数据。
Radix Tree
不支持范围存储,每个键值对需要单独存储。
适合管理单一索引的稀疏数据。
3. 应用场景 3.1 maple_tree
的应用场景
虚拟内存管理(VMA) :
管理虚拟地址空间的范围映射。
替代红黑树(rb_tree
)以提高效率。
文件系统元数据 :
内存分配器 :
高并发读写场景 :
3.2 Radix Tree
的应用场景
页缓存(Page Cache) :
ID 分配(IDR/IDA) :
实现 ID 分配器(IDR)和 ID 分配助手(IDA)。
稀疏数据管理 :
低复杂度操作 :
4. 异同点 4.1 相似点
目标 : 都是为了高效管理稀疏数据。
并发支持 : 都使用 RCU 支持无锁读操作。
内核应用 : 都广泛应用于 Linux 内核的核心子系统(如内存管理、文件系统等)。
4.2 不同点
特性
maple_tree
Radix Tree
数据结构
多叉树
压缩前缀树
范围操作
原生支持
不支持
内存占用
更低(通过多叉节点减少树的高度)
较高(每个键值对单独存储)
并发支持
RCU + 写锁,读写性能更高
RCU + 写锁,写操作性能稍逊
典型应用
虚拟地址空间(VMA)、文件元数据
页缓存(Page Cache)、ID 分配
5. 总结与选择建议
选择 maple_tree
:
如果需要范围操作(如虚拟地址空间管理)。
如果需要更低的内存占用和更高的查找效率。
如果需要在高并发环境下高效读写。
选择 Radix Tree
:
如果需要管理稀疏的单值数据(如页缓存或 ID 分配)。
如果范围操作不是主要需求。
maple_tree
是对 Radix Tree
的一种优化和扩展,特别适合范围操作和高并发场景,而 Radix Tree
在单一索引稀疏数据的管理中仍然表现优异。两者各有优势,根据具体的应用场景选择合适的数据结构可以更好地满足系统需求。
include/linux/maple_tree.h maple_status Maple State 状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ma enum maple_status { ma_active, ma_start, ma_root, ma_none, ma_pause, ma_overflow, ma_underflow, ma_error, };
maple_range_64 叶节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 struct maple_range_64 { struct maple_pnode *parent ; unsigned long pivot[MAPLE_RANGE64_SLOTS - 1 ]; union { void __rcu *slot[MAPLE_RANGE64_SLOTS]; struct { void __rcu *pad[MAPLE_RANGE64_SLOTS - 1 ]; struct maple_metadata meta ; }; }; };
struct ma_state 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 struct ma_state { struct maple_tree *tree ; unsigned long index; unsigned long last; struct maple_enode *node ; unsigned long min; unsigned long max; struct maple_alloc *alloc ; enum maple_status status ; unsigned char depth; unsigned char offset; unsigned char mas_flags; unsigned char end; enum store_type store_type ; }; struct ma_wr_state { struct ma_state *mas ; struct maple_node *node ; unsigned long r_min; unsigned long r_max; enum maple_type type ; unsigned char offset_end; unsigned long *pivots; unsigned long end_piv; void __rcu **slots; void *entry; void *content; };
MA_STATE 表示 Maple Tree 的操作状态 1 2 3 4 5 6 7 8 9 10 11 12 13 #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, \ .alloc = NULL, \ .mas_flags = 0, \ .store_type = wr_invalid, \ }
MA_WR_STATE 表示写操作状态 1 2 3 4 5 6 #define MA_WR_STATE(name, ma_state, wr_entry) \ struct ma_wr_state name = { \ .mas = ma_state, \ .content = NULL, \ .entry = wr_entry, \ }
MTREE_INIT 初始化 Maple Tree 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 struct maple_tree { union { spinlock_t ma_lock; lockdep_map_p ma_external_lock; }; unsigned int ma_flags; void __rcu *ma_root; }; #define MTREE_INIT(name, __flags) { \ .ma_lock = __SPIN_LOCK_UNLOCKED((name).ma_lock), \ .ma_flags = __flags, \ .ma_root = NULL, \ } #define MTREE_INIT_EXT(name, __flags, __lock) MTREE_INIT(name, __flags)
lib/maple_tree.c maple_tree_init 1 2 3 4 5 6 void __init maple_tree_init (void ) { maple_node_cache = kmem_cache_create("maple_node" , sizeof (struct maple_node), sizeof (struct maple_node), SLAB_PANIC, NULL ); }
mas_root 获取枫树根 1 2 3 4 5 6 7 8 9 10 static __always_inline void *mas_root (struct ma_state *mas) { return rcu_dereference_check(mas->tree->ma_root, mt_locked(mas->tree)); }
mas_start 设置 Maple 状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 static inline struct maple_enode *mas_start (struct ma_state *mas) { if (likely(mas_is_start(mas))) { struct maple_enode *root ; mas->min = 0 ; mas->max = ULONG_MAX; retry: mas->depth = 0 ; root = mas_root(mas); if (likely(xa_is_node(root))) { mas->depth = 1 ; mas->status = ma_active; mas->node = mte_safe_root(root); mas->offset = 0 ; if (mte_dead_node(mas->node)) goto retry; return NULL ; } mas->node = NULL ; if (unlikely(!root)) { mas->status = ma_none; mas->offset = MAPLE_NODE_SLOTS; return NULL ; } mas->status = ma_root; mas->offset = MAPLE_NODE_SLOTS; if (mas->index > 0 ) return NULL ; return root; } return NULL ; }
mas_wr_prealloc_setup mas写预分配设置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 static inline void mas_wr_prealloc_setup (struct ma_wr_state *wr_mas) { struct ma_state *mas = wr_mas->mas; if (!mas_is_active(mas)) { if (mas_is_start(mas)) goto set_content; if (unlikely(mas_is_paused(mas))) goto reset; if (unlikely(mas_is_none(mas))) goto reset; if (unlikely(mas_is_overflow(mas))) goto reset; if (unlikely(mas_is_underflow(mas))) goto reset; } if (mas->last > mas->max) goto reset; if (wr_mas->entry) goto set_content; if (mte_is_leaf(mas->node) && mas->last == mas->max) goto reset; goto set_content; reset: mas_reset(mas); set_content: wr_mas->content = mas_start(mas); }
mas_wr_store_type 获取存储类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 static inline enum store_type mas_wr_store_type (struct ma_wr_state *wr_mas) { struct ma_state *mas = wr_mas->mas; unsigned char new_end; if (unlikely(mas_is_none(mas) || mas_is_ptr(mas))) return wr_store_root; if (unlikely(!mas_wr_walk(wr_mas))) return wr_spanning_store; mas_wr_end_piv(wr_mas); if (!wr_mas->entry) mas_wr_extend_null(wr_mas); if ((wr_mas->r_min == mas->index) && (wr_mas->r_max == mas->last)) return wr_exact_fit; if (unlikely(!mas->index && mas->last == ULONG_MAX)) return wr_new_root; new_end = mas_wr_new_end(wr_mas); if (new_end < mt_min_slots[wr_mas->type]) { if (!mte_is_root(mas->node) && !(mas->mas_flags & MA_STATE_BULK)) return wr_rebalance; return wr_node_store; } if (new_end >= mt_slots[wr_mas->type]) return wr_split_store; if (!mt_in_rcu(mas->tree) && (mas->offset == mas->end)) return wr_append; if ((new_end == mas->end) && (!mt_in_rcu(mas->tree) || (wr_mas->offset_end - mas->offset == 1 ))) return wr_slot_store; return wr_node_store; }
mas_prealloc_calc 计算给定 store 运行所需的节点数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 static inline int mas_prealloc_calc (struct ma_state *mas, void *entry) { int ret = mas_mt_height(mas) * 3 + 1 ; switch (mas->store_type) { case wr_invalid: WARN_ON_ONCE(1 ); break ; case wr_new_root: ret = 1 ; break ; case wr_store_root: if (likely((mas->last != 0 ) || (mas->index != 0 ))) ret = 1 ; else if (((unsigned long ) (entry) & 3 ) == 2 ) ret = 1 ; else ret = 0 ; break ; case wr_spanning_store: ret = mas_mt_height(mas) * 3 + 1 ; break ; case wr_split_store: ret = mas_mt_height(mas) * 2 + 1 ; break ; case wr_rebalance: ret = mas_mt_height(mas) * 2 - 1 ; break ; case wr_node_store: ret = mt_in_rcu(mas->tree) ? 1 : 0 ; break ; case wr_append: case wr_exact_fit: case wr_slot_store: ret = 0 ; } return ret; }
mas_allocated 获取在 Maple 状态下分配的节点数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static inline unsigned long mas_allocated (const struct ma_state *mas) { if (!mas->alloc || ((unsigned long )mas->alloc & 0x1 )) return 0 ; return mas->alloc->total; }
mas_set_alloc_req 设置请求的分配数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static inline void mas_set_alloc_req (struct ma_state *mas, unsigned long count) { if (!mas->alloc || ((unsigned long )mas->alloc & 0x1 )) { if (!count) mas->alloc = NULL ; else mas->alloc = (struct maple_alloc *)(((count) << 1U ) | 1U ); return ; } mas->alloc->request_count = count; }
mas_alloc_req 获取请求的分配数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static inline unsigned int mas_alloc_req (const struct ma_state *mas) { if ((unsigned long )mas->alloc & 0x1 ) return (unsigned long )(mas->alloc) >> 1 ; else if (mas->alloc) return mas->alloc->request_count; return 0 ; }
mt_alloc_one 分配一个 Maple 节点 1 2 3 4 static inline struct maple_node *mt_alloc_one (gfp_t gfp) { return kmem_cache_alloc(maple_node_cache, gfp); }
mas_alloc_nodes 将节点分配到 Maple 状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 static inline void mas_alloc_nodes (struct ma_state *mas, gfp_t gfp) { struct maple_alloc *node ; unsigned long allocated = mas_allocated(mas); unsigned int requested = mas_alloc_req(mas); unsigned int count; void **slots = NULL ; unsigned int max_req = 0 ; if (!requested) return ; mas_set_alloc_req(mas, 0 ); if (mas->mas_flags & MA_STATE_PREALLOC) { if (allocated) return ; WARN_ON(!allocated); } if (!allocated || mas->alloc->node_count == MAPLE_ALLOC_SLOTS) { node = (struct maple_alloc *)mt_alloc_one(gfp); if (!node) goto nomem_one; if (allocated) { node->slot[0 ] = mas->alloc; node->node_count = 1 ; } else { node->node_count = 0 ; } mas->alloc = node; node->total = ++allocated; node->request_count = 0 ; requested--; } node = mas->alloc; while (requested) { max_req = MAPLE_ALLOC_SLOTS - node->node_count; slots = (void **)&node->slot[node->node_count]; max_req = min(requested, max_req); count = mt_alloc_bulk(gfp, max_req, slots); if (!count) goto nomem_bulk; if (node->node_count == 0 ) { node->slot[0 ]->node_count = 0 ; node->slot[0 ]->request_count = 0 ; } node->node_count += count; allocated += count; do { node = node->slot[0 ]; } while (unlikely(node->node_count == MAPLE_ALLOC_SLOTS)); requested -= count; } mas->alloc->total = allocated; return ; nomem_bulk: memset (slots, 0 , max_req * sizeof (unsigned long )); mas->alloc->total = allocated; nomem_one: mas_set_alloc_req(mas, requested); mas_set_err(mas, -ENOMEM); }
mas_node_count 计算节点数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 static void mas_node_count_gfp (struct ma_state *mas, int count, gfp_t gfp) { unsigned long allocated = mas_allocated(mas); if (allocated < count) { mas_set_alloc_req(mas, count - allocated); mas_alloc_nodes(mas, gfp); } } static void mas_node_count (struct ma_state *mas, int count) { return mas_node_count_gfp(mas, count, GFP_NOWAIT | __GFP_NOWARN); }
mas_wr_preallocate 为存储作预分配足够的节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static inline void mas_wr_preallocate (struct ma_wr_state *wr_mas, void *entry) { struct ma_state *mas = wr_mas->mas; int request; mas_wr_prealloc_setup(wr_mas); mas->store_type = mas_wr_store_type(wr_mas); request = mas_prealloc_calc(mas, entry); if (!request) return ; mas_node_count(mas, request); }
mas_pop_node 从 maple 状态获取先前分配的 maple 节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 static inline struct maple_node *mas_pop_node (struct ma_state *mas) { struct maple_alloc *ret , *node = mas->alloc; unsigned long total = mas_allocated(mas); unsigned int req = mas_alloc_req(mas); if (WARN_ON(!total)) return NULL ; if (total == 1 ) { mas->alloc = NULL ; ret = node; goto single_node; } if (node->node_count == 1 ) { mas->alloc = node->slot[0 ]; mas->alloc->total = node->total - 1 ; ret = node; goto new_head; } node->total--; ret = node->slot[--node->node_count]; node->slot[node->node_count] = NULL ; single_node: new_head: if (req) { req++; mas_set_alloc_req(mas, req); } memset (ret, 0 , sizeof (*ret)); return (struct maple_node *)ret; }
mas_root_expand 将根扩展为节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 static inline void mas_root_expand (struct ma_state *mas, void *entry) { void *contents = mas_root_locked(mas); enum maple_type type = maple_leaf_64; struct maple_node *node ; void __rcu **slots; unsigned long *pivots; int slot = 0 ; node = mas_pop_node(mas); pivots = ma_pivots(node, type); slots = ma_slots(node, type); node->parent = ma_parent_ptr(mas_tree_parent(mas)); mas->node = mt_mk_node(node, type); mas->status = ma_active; if (mas->index) { if (contents) { rcu_assign_pointer(slots[slot], contents); if (likely(mas->index > 1 )) slot++; } pivots[slot++] = mas->index - 1 ; } rcu_assign_pointer(slots[slot], entry); mas->offset = slot; pivots[slot] = mas->last; if (mas->last != ULONG_MAX) pivots[++slot] = ULONG_MAX; mas->depth = 1 ; mas_set_height(mas); ma_set_meta(node, maple_leaf_64, 0 , slot); rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node)); return ; }
mas_store_root 将值存储到 root 中 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static inline void mas_store_root (struct ma_state *mas, void *entry) { if (!entry) { if (!mas->index) rcu_assign_pointer(mas->tree->ma_root, NULL ); } else if (likely((mas->last != 0 ) || (mas->index != 0 ))) mas_root_expand(mas, entry); else if (((unsigned long ) (entry) & 3 ) == 2 ) mas_root_expand(mas, entry); else { rcu_assign_pointer(mas->tree->ma_root, entry); mas->status = ma_start; } }
mas_wr_store_entry 用于存储值的内部调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 static inline void mas_wr_store_entry (struct ma_wr_state *wr_mas) { struct ma_state *mas = wr_mas->mas; unsigned char new_end = mas_wr_new_end(wr_mas); switch (mas->store_type) { case wr_invalid: MT_BUG_ON(mas->tree, 1 ); return ; case wr_new_root: mas_new_root(mas, wr_mas->entry); break ; case wr_store_root: mas_store_root(mas, wr_mas->entry); break ; case wr_exact_fit: rcu_assign_pointer(wr_mas->slots[mas->offset], wr_mas->entry); if (!!wr_mas->entry ^ !!wr_mas->content) mas_update_gap(mas); break ; case wr_append: mas_wr_append(wr_mas, new_end); break ; case wr_slot_store: mas_wr_slot_store(wr_mas); break ; case wr_node_store: mas_wr_node_store(wr_mas, new_end); break ; case wr_spanning_store: mas_wr_spanning_store(wr_mas); break ; case wr_split_store: case wr_rebalance: mas_wr_bnode(wr_mas); break ; } return ; }
mas_store_gfp 将值存储到树中 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 int mas_store_gfp (struct ma_state *mas, void *entry, gfp_t gfp) { unsigned long index = mas->index; unsigned long last = mas->last; MA_WR_STATE(wr_mas, mas, entry); int ret = 0 ; retry: mas_wr_preallocate(&wr_mas, entry); if (unlikely(mas_nomem(mas, gfp))) { if (!entry) __mas_set_range(mas, index, last); goto retry; } if (mas_is_err(mas)) { ret = xa_err(mas->node); goto out; } mas_wr_store_entry(&wr_mas); out: mas_destroy(mas); return ret; } EXPORT_SYMBOL_GPL(mas_store_gfp);
tree_load: 从枫树中加载一个值 此函数是Linux内核中“枫树”(Maple Tree)数据结构的核心读取操作接口。它的作用是根据给定的索引(index
),在指定的枫树(mt
)中高效地查找并返回存储在该索引处的数据条目(一个指针)。枫树是一种为稀疏、大范围的无符号长整型索引设计的、对CPU缓存友好的B-树,它的查找性能非常高。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 void *mtree_load (struct maple_tree *mt, unsigned long index) { MA_STATE(mas, mt, index, index); void *entry; trace_ma_read(__func__, &mas); rcu_read_lock(); retry: entry = mas_start(&mas); if (unlikely(mas_is_none(&mas))) goto unlock; if (unlikely(mas_is_ptr(&mas))) { if (index) entry = NULL ; goto unlock; } entry = mtree_lookup_walk(&mas); if (!entry && unlikely(mas_is_start(&mas))) goto retry; unlock: rcu_read_unlock(); if (xa_is_zero(entry)) return NULL ; return entry; } EXPORT_SYMBOL(mtree_load);