Linux黑科技mmap实现揭秘

莱科网
预计阅读时长 7 分钟
位置: 首页 未命名 正文

 

答案就是:缺页异常:

Linux黑科技mmap实现揭秘

由于 mmap() 系统调用并没有直接将文件的页缓存映射到虚拟内存中,所以当访问到没有映射的虚拟内存地址时,将会触发 缺页异常。当 CPU 触发缺页异常时,将会调用 do_page_fault() 函数来修复触发异常的虚拟内存地址。

我们主要来看看 do_page_fault() 函数对文件映射的实现部分,其调用链如下:

do_page_fault()
└→ handle_mm_fault()
   └→ handle_pte_fault()
      └→ do_linear_fault()
         └→ __do_fault()
登录后复制

所以我们直接来看看 __do_fault() 函数的实现:

static int
__do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
           unsigned long address, pmd_t *pmd, pgoff_t pgoff,
           unsigned int flags, pte_t orig_pte)
{
    ...
    vmf.virtual_address = address & PAGE_MASK; // 要映射的虚拟内存地址
    vmf.pgoff = pgoff;                         // 映射到文件的偏移量
    vmf.flags = flags;                         // 标志位
    vmf.page = NULL;                           // 映射到虚拟内存中的物理内存页

    // 1. 如果虚拟内存管理区提供了 falut() 回调函数,那么将调用此函数来获取要映射的物理内存页,
    //    我们在 mmap() 系统调用的实现中看到,已经将其设置为 filemap_fault() 函数了。
    if (likely(vma->vm_ops->fault)) {
        ret = vma->vm_ops->fault(vma, &vmf);
        ...
    }
    ...

    if (likely(pte_same(*page_table, orig_pte))) {
        ...
        // 2. 通过物理内存页生成一个页表项值
        entry = mk_pte(page, vma->vm_page_prot);
        if (flags & FAULT_FLAG_WRITE)
            entry = maybe_mkwrite(pte_mkdirty(entry), vma);

        // 3. 将虚拟内存地址映射到物理内存
        set_pte_at(mm, address, page_table, entry);
        ...
    }
    ...

    return ret;
}
登录后复制

__do_fault() 函数对处理文件映射部分主要分为 3 个步骤:

调用虚拟内存管理区结构的 fault() 回调函数来获取到文件的页缓存。 通过页缓存的物理内存页来生成一个页表项值,可以参考《漫画解说 “内存映射”》一文。 将虚拟内存地址映射到页缓存的物理内存页。

对于 filemap_fault() 函数是怎样读取文件页缓存的,本文不作解释,有兴趣的可以自行阅读源码。

最后,我们以一幅图来描述一下虚拟内存是如何与文件进行映射的:

从上图可以看出,mmap() 是通过将虚拟内存地址映射到文件的页缓存来实现的。当对映射后的虚拟内存进行读写操作时,其效果等价于直接对文件的页缓存进行读写操作。对文件的页缓存进行读写操作,也等价于对文件进行读写操作。

本文来自投稿,不代表本站立场,如若转载,请注明出处:
-- 展开阅读全文 --
头像
linux-autoconf自动更新解析
« 上一篇 2025-01-26 16:02:17
深入解析Linux线程与信号关系
下一篇 » 2025-01-26 16:06:10

相关文章

取消
微信二维码
支付宝二维码

热门文章

动态快讯

目录[+]