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!
