第6章:虚拟内存区域 (VMA)
基于 Linux 6.12.38 源码
6.1 VMA 概述
6.1.1 什么是 VMA
VMA (Virtual Memory Area,虚拟内存区域) 表示进程地址空间中的一个连续区域,每个 VMA 具有相同的访问权限和属性。
VMA 特点:
- 连续的虚拟地址范围
- 相同的访问权限 (读/写/执行)
- 相同的映射类型 (文件映射、匿名映射)
- 每个进程的地址空间由多个 VMA 组成
6.1.2 VMA 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 进程地址空间: ┌─────────────────────────────────────────────────────────────┐ │ │ │ 0x400000 ────┐ 代码段 (VMA1) │ │ │ - 可读、可执行 │ │ 0x401000 ────┘ │ │ │ │ 0x600000 ────┐ 数据段 (VMA2) │ │ │ - 可读、可写 │ │ 0x601000 ────┘ │ │ │ │ 0x7fff0000 ─┐ 栈段 (VMA3) │ │ │ - 可读、可写、向下增长 │ │ 0x7ffffffff┘ │ │ │ │ mmap 区域 (多个 VMA): │ │ - 动态库映射 │ │ - 共享内存 │ │ - 匿名映射 │ │ │ └─────────────────────────────────────────────────────────────┘
|
6.2 vm_area_struct 结构
6.2.1 结构定义
位置: include/linux/mm_types.h:697
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
| struct vm_area_struct {
union { struct { unsigned long vm_start; unsigned long vm_end; }; #ifdef CONFIG_PER_VMA_LOCK struct rcu_head vm_rcu; #endif };
struct mm_struct *vm_mm; pgprot_t vm_page_prot;
union { const vm_flags_t vm_flags; vm_flags_t __private __vm_flags; };
#ifdef CONFIG_PER_VMA_LOCK
bool detached;
int vm_lock_seq;
struct vma_lock *vm_lock; #endif
struct { struct rb_node rb; unsigned long rb_subtree_last; } shared;
struct list_head anon_vma_chain; struct anon_vma *anon_vma;
const struct vm_operations_struct *vm_ops;
unsigned long vm_pgoff; struct file *vm_file; void *vm_private_data;
#ifdef CONFIG_ANON_VMA_NAME
struct anon_vma_name *anon_name; #endif #ifdef CONFIG_SWAP atomic_long_t swap_readahead_info; #endif #ifndef CONFIG_MMU struct vm_region *vm_region; #endif #ifdef CONFIG_NUMA struct mempolicy *vm_policy; #endif #ifdef CONFIG_NUMA_BALANCING struct vma_numab_state *numab_state; #endif struct vm_userfaultfd_ctx vm_userfaultfd_ctx; } __randomize_layout;
|
6.2.2 VMA 核心字段
| 字段 |
描述 |
vm_start |
VMA 起始虚拟地址 |
vm_end |
VMA 结束虚拟地址 (不包含) |
vm_mm |
所属的 mm_struct |
vm_page_prot |
页保护权限 |
vm_flags |
VMA 标志 |
vm_ops |
VMA 操作函数 |
vm_file |
映射的文件 (可为 NULL) |
vm_pgoff |
文件偏移 (页为单位) |
6.3 VMA 标志
6.3.1 VMA 标志定义
位置: include/linux/mm.h
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
| #define VM_READ 0x00000001 #define VM_WRITE 0x00000002 #define VM_EXEC 0x00000004 #define VM_SHARED 0x00000008
#define VM_MAYREAD 0x00000010 #define VM_MAYWRITE 0x00000020 #define VM_MAYEXEC 0x00000040 #define VM_MAYSHARE 0x00000080
#define VM_GROWSDOWN 0x00000100 #define VM_GROWSUP 0x00000200 #define VM_PFNMAP 0x00000400 #define VM_DENYWRITE 0x00000800 #define VM_IO 0x00004000 #define VM_LOCKED 0x00008000 #define VM_SEQ_READ 0x00010000 #define VM_RAND_READ 0x00020000 #define VM_DONTCOPY 0x00040000 #define VM_DONTEXPAND 0x00080000 #define VM_LOCKONFAULT 0x00100000 #define VM_ACCOUNT 0x00200000 #define VM_NORESERVE 0x00400000 #define VM_HUGETLB 0x00400000 #define VM_SYNC 0x00800000 #define VM_ARCH_1 0x01000000 #define VM_WIPEONFORK 0x02000000 #define VM_DONTDUMP 0x04000000 #define VM_MIXEDMAP 0x10000000 #define VM_HUGESPACE 0x40000000 #define VM_SOFTDIRTY 0x80000000
|
6.3.2 标志操作函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| static inline void vm_flags_init(struct vm_area_struct *vma, vm_flags_t flags);
static inline void vm_flags_reset(struct vm_area_struct *vma, vm_flags_t flags);
static inline void vm_flags_set(struct vm_area_struct *vma, vm_flags_t flags);
static inline void vm_flags_clear(struct vm_area_struct *vma, vm_flags_t flags);
static inline void vm_flags_mod(struct vm_area_struct *vma, vm_flags_t set, vm_flags_t clear);
|
6.4 VMA 操作
6.4.1 vm_operations_struct
位置: include/linux/mm.h
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
| struct vm_operations_struct { void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
vm_fault_t (*fault)(struct vm_fault *vmf);
vm_fault_t (*page_mkwrite)(struct vm_fault *vmf);
vm_fault_t (*pfn_mkwrite)(struct vm_fault *vmf);
vm_fault_t (*access)(struct vm_fault *vmf);
vm_fault_t (*split)(struct vm_fault *vmf);
vm_fault_t (*pmd_fault)(struct vm_fault *vmf, unsigned long address);
unsigned long (*pagesize)(struct vm_area_struct * area);
int (*mprotect)(struct vm_area_struct *vma, unsigned long start, unsigned long end, unsigned long newflags);
void (*vma_name)(struct vm_area_struct *vma, char *name, size_t count); };
|
6.4.2 VMA 查找操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr);
struct vm_area_struct *lock_vma_under_rcu(struct mm_area_struct *mm, unsigned long addr);
struct vm_area_struct *find_vma_prev(struct mm_struct *mm, unsigned long addr, struct vm_area_struct **pprev);
struct vm_area_struct *find_vma_intersection(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr);
|
6.4.3 VMA 创建/删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma);
struct vm_area_struct *vm_area_alloc(struct mm_struct *mm);
void vm_area_free(struct vm_area_struct *vma);
struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, pgprot_t vm_prot, struct mempolicy *policy, unsigned long vm_pgoff, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff);
|
6.5 VMA 管理
6.5.1 Maple Tree 管理
Linux 5.13+ 使用 Maple Tree 管理 VMA,替代了之前的红黑树。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void __vma_link_list(struct vm_area_struct *vma, struct vm_area_struct *prev, struct vm_area_struct *next);
void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma);
struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr);
struct vm_area_struct *vma_first(struct mm_struct *mm);
struct vm_area_struct *vma_next(struct vm_area_struct *vma);
struct vm_area_struct *vma_prev(struct vm_area_struct *vma);
|
6.5.2 VMA 分裂和合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, int new_below);
struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, pgprot_t vm_prot, struct mempolicy *policy, unsigned long vm_pgoff, struct anon_vma *anon_vma, struct file *file);
int vma_can_merge(struct vm_area_struct *vma, struct vm_area_struct *next);
|
6.5.3 VMA 调整大小
1 2 3 4 5 6 7 8 9 10 11
| int expand_stack(struct vm_area_struct *vma, unsigned long address);
struct vm_area_struct *expand_vma(struct vm_area_struct *vma, unsigned long delta);
int vma_adjust(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert);
|
6.6 匿名 VMA
6.6.1 anon_vma 结构
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct anon_vma { struct anon_vma *root; struct rw_semaphore rwsem; atomic_long_t refcount;
struct rb_root_cached rb_root;
struct list_head head; };
|
6.6.2 anon_vma_chain
1 2 3 4 5 6 7
| struct anon_vma_chain { struct vm_area_struct *vma; struct anon_vma *anon_vma; struct list_head same_vma; struct rb_node rb; unsigned long rb_subtree_last; };
|
6.6.3 匿名 VMA 操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct anon_vma *anon_vma_alloc(void); void anon_vma_free(struct anon_vma *anon_vma);
int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma);
struct anon_vma *page_get_anon_vma(struct page *page);
struct anon_vma_name *anon_vma_name_alloc(const char *name); void anon_vma_name_free(struct kref *kref);
|
6.7 VMA 锁
6.7.1 Per-VMA Lock
Linux 6.1+ 引入了 Per-VMA 锁机制,减少 mmap_lock 的竞争。
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct vma_lock { struct rw_semaphore lock; };
void vma_start_read(struct vm_area_struct *vma); void vma_end_read(struct vm_area_struct *vma); void vma_start_write(struct vm_area_struct *vma); void vma_end_write(struct vm_area_struct *vma);
bool vma_start_read_trylock(struct vm_area_struct *vma); bool vma_start_write_trylock(struct vm_area_struct *vma);
|
6.7.2 锁定顺序
1 2 3 4 5 6 7 8
| VMA 锁的锁定顺序: 1. mmap_lock (读或写) 2. vm_lock->lock (读或写)
VMA 锁的使用场景: - 缺页处理 - 页面错误处理 - VMA 查找
|
6.8 本章小结
本章介绍了 Linux 6.12 的虚拟内存区域 (VMA):
- VMA 概述: 进程地址空间中的连续区域,相同权限和属性
- vm_area_struct: VMA 核心数据结构
- VMA 标志: 访问权限、增长方向、映射类型等
- VMA 操作: 查找、创建、删除、合并、分裂
- Maple Tree: Linux 5.13+ 使用的 VMA 管理数据结构
- 匿名 VMA: 匿名映射的 VMA 管理
- VMA 锁: Per-VMA 锁机制,减少竞争
下一章将介绍页面分配。