深入理解Linux内核之mmu-gather操作

💡 原文中文,约17600字,阅读约需42分钟。
📝

内容提要

在Linux内核的虚拟内存管理中,mmu_gather操作用于解除映射的物理页面,并确保正确的刷新tlb和释放物理页面的顺序。操作包括解除页表映射、刷新tlb、释放物理页面。相关的数据结构有mmu_gather、mmu_table_batch和mmu_gather_batch。应用场景包括进程退出、执行execv和调用munmap。

🔎

延伸解读

顺序约束:为何不能先释放物理页

文章强调,在刷新TLB之前释放物理页可能导致不正确结果。因为TLB中可能仍缓存着旧映射,若物理页被提前释放并重用,CPU可能通过旧TLB项访问到已改变用途的内存。mmu-gather通过先解除映射、再刷新TLB、最后释放物理页的顺序来避免此风险,这是该机制存在的核心原因。

本地批次与多批次的设计权衡

mmu_gather结构内嵌的__pages数组仅能容纳8个页面(32KB),因为该结构通常分配在内核栈上,不能占用过多栈空间。当积聚页面超过8个时,会动态分配mmu_gather_batch结构来容纳更多页面,形成批次链表。这种设计在栈空间限制与批量释放效率之间取得了平衡。

页表释放的RCU延迟与批次限制

对于存放各级页目录的物理页,mmu_table_batch使用RCU延迟释放,并通过tlb_remove_table_free调用call_rcu来确保安全。与物理页积聚不同,页表积聚结构填满后立即释放,不会构建批次链表。此外,批次数量受MAX_GATHER_BATCH_COUNT限制,以避免非抢占内核下的soft lockup。

应用场景的共性与差异

进程退出、执行execv和调用munmap都会触发mmu-gather操作,但范围不同:进程退出和execv释放整个地址空间(start=0, end=-1),而munmap仅释放指定范围。三者都遵循相同的四步调用链:tlb_gather_mmu初始化、unmap_vmas解除映射并积聚页面、free_pgtables释放页表、tlb_finish_mmu刷新TLB并释放所有积聚页面。

❓

Q&A

mmu_gather操作的主要功能是什么?

mmu_gather操作用于解除映射的物理页面,并确保正确刷新tlb和释放物理页面的顺序。

mmu_gather操作的步骤有哪些?

操作步骤包括解除页表映射、刷新tlb、释放物理页面。

mmu_gather相关的数据结构有哪些?

相关的数据结构包括mmu_gather、mmu_table_batch和mmu_gather_batch。

mmu_gather操作的应用场景是什么?

mmu_gather的应用场景主要包括进程退出、执行execv和调用munmap等操作。

mmu_gather操作中如何确保tlb的刷新顺序?

在刷新相关虚拟内存区域的tlb之前,绝对不能提前释放物理页面,以确保正确的顺序。

mmu_gather操作涉及哪些函数?

mmu-gather操作通常由tlb_gather_mmu、unmap_vmas、free_pgtables和tlb_finish_mmu等函数组成。

🏷️

标签

➡️

继续阅读