Linux内核mmgrab、mmdrop、mmput函数用法详解
mmgrab、mmdrop mmput函数用法
在 Linux 内核开发中,mmgrab()
、mmdrop()
和 mmput()
是用于管理 struct mm_struct
(进程地址空间描述符)引用计数的核心函数。以下是它们的详细用法和区别:
1. mmgrab()
- 功能:增加
mm_struct
的用户引用计数(mm->mm_users
)。 - 使用场景:
- 需要短期访问进程内存空间时(如内核线程处理用户请求)。
- 确保目标
mm_struct
在操作期间不被释放。
- 示例:
1
2
3
4
5
6struct mm_struct *mm = get_task_mm(task); // 获取目标任务的 mm_struct(已增加引用)
if (mm) {
mmgrab(mm); // 显式增加引用计数(可选,因 get_task_mm 已增加)
// 安全操作 mm(如访问页表)
mmput(mm); // 操作完成后减少引用
} - 注意:
mmgrab()
仅增加计数,不检查计数是否为零。
2. mmput()
- 功能:减少
mm_struct
的用户引用计数(mm->mm_users
)。若计数归零:- 释放内存映射(
exit_mmap()
)。 - 减少内核引用计数(
mm->mm_count
)。 - 若
mm_count
归零,彻底销毁mm_struct
。
- 释放内存映射(
- 使用场景:
- 配对
mmgrab()
或get_task_mm()
,释放不再需要的引用。
- 配对
- 示例:
1
2
3
4
5
6
7void process_mm(struct task_struct *task) {
struct mm_struct *mm = get_task_mm(task); // 获取 mm(增加 mm_users)
if (!mm) return;
// 操作 mm...
mmput(mm); // 释放引用,若 mm_users 归零则触发清理
}
3. mmdrop()
- 功能:减少
mm_struct
的内核引用计数(mm->mm_count
)。 - 使用场景:
- 仅在内核核心代码中管理
mm_count
(如mmput()
内部或 RCU 回调)。 - 普通模块/驱动中禁止直接使用。
- 仅在内核核心代码中管理
- 与
mmput()
的区别:函数 操作的计数器 是否触发资源释放 适用场景 mmput()
mm_users
是(归零时) 用户引用释放 mmdrop()
mm_count
否(需手动处理) 内核底层内存管理 - 示例(仅在内核核心代码中):
1
2
3
4
5
6
7// mmput() 内部简化逻辑
void mmput(struct mm_struct *mm) {
if (atomic_dec_and_test(&mm->mm_users)) { // mm_users 归零
exit_mmap(mm); // 释放内存映射
mmdrop(mm); // 减少 mm_count,若归零则释放 mm_struct
}
}
关键规则
配对使用:
mmgrab()
/get_task_mm()
必须与mmput()
成对调用。1
2
3struct mm_struct *mm = get_task_mm(task); // 或 mmgrab()
// ... 操作 ...
mmput(mm); // 确保释放**禁止直接使用
mmdrop()
**:
除非在核心内存管理代码中(如实现自定义销毁逻辑),否则永远不要调用mmdrop()
。引用计数类型:
mm_users
:用户引用数(如进程、线程),归零时释放内存映射。mm_count
:内核引用数(如lru
列表),归零时释放mm_struct
自身。
典型工作流
1 | // 1. 获取 mm_struct 引用 |
注意:操作
mm_struct
时通常需配合mmap_lock
(读写信号量)确保并发安全。
如有疑问,建议查阅内核源码(mm/memory.c
、kernel/fork.c
)或特定版本文档。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Helloeuler!