Linux内核 内存映射文件机制mmap

        今天研究Linux1.2内核运行加载a.out格式的可执行文件的代码时,无意中研究明白了内核提供的内存映射机制--mmap(memory map)。

当内核要加载可执行文件到相应的用户地址空间时,有两种方式。第一种就是“按需加载”,也就是我们所说的mmap机制。内核调用do_mmap()函数,建立代表进程虚拟地址空间的vma,并将vma与可执行文件的i节点以及可执行文件所在的文件系统的相关操作函数联系起来。在1.2内核中,就是讲可执行文件的i节点赋给vma->vm_inode,将通用的mmap函数generic_map()赋给vm->ops。这就可以了,这时,内核将可执行文件映射到了进程的虚拟地址空间vma中,但这只是一个映射,内核并没有将可执行文件读入内存,可执行文件此时还放在磁盘上。但此时已经做到可以按需加载了,当CPU执行时发现要执行的可执行文件的代码或访问的数据不在内存时,就产生缺页中断,在缺页中断处理程序中,内核判断出还未访问过此页,于是就调用vma->ops->nopage(),即通用mmap函数generic_mmap(),函数会根据缺页地址计算出可执行文件的逻辑和物理磁盘块号,从而将此块读入内存。这就是按需加载。

        第二种方式就是直接全部加载可执行文件至内存。内核以匿名方式调用do_mmap()函数,这种方式的意义在于只申请和建立相应的进程虚拟地址空间vma,然后将进程相应的表项全部映射到内核“零页”,并且设置写保护。此时,已经建立了进程可执行文件的虚拟地址空间,但并没有映射和加载可执行文件。而后,内核会调用read_exec()函数,调用将可执行文件所在文件系统的文件读写函数,将可执行文件全部读入进程地址空间并建立进程表项。此时,可执行文件全部加载至内存。有意思的是,内核匿名映射的时候,是将进程相应表项全部映射到内核的同一个“零页”,那么,内核是如何完成“零页”到可执行文件内容的替换的呢?答案就是写时复制机制(可以这么理解,但严格来说,不是写时复制,因为映射的是内核页面,请参考我的博客“对Linux0.11 "内核空间不使用写时复制机制" 本质理解”)。虽然进程相应页表项全部映射到同一个内核“零页”,但这种映射是具有写保护性质的。内核执行read_exec()函数时,要将可执行文件从磁盘读出,那么,读出来以后,放到哪呢?当然是进程相应的地址空间了(从0开始)。内核先调用verify_area()函数验证用户空间是否可写,内核发现相应的地址空间映射的是内核页面,相当于共享了内核页面,但内核页面是不可写的,所以内核申请一页新的物理内存,将零页的内容复制到页面中,就是这个过程将用户地址空间脱离内核“零页”,使用户地址空间有了自己的物理页面。最后,内核调用文件的读写函数,将可执行文件读入到这些物理页面。此时,可执行文件就全部加载至内存了。

        对于第二种方式,是因为有些文件系统不支持mmap(和可执行文件格式无关,而和具体的文件系统有关)。根本原因是其不支持bmap()函数,此函数可以根据文件的逻辑块号计算出其在磁盘上的磁盘块号,进而当缺页中断发生时,可以将此块读入内存。我觉得一般的文件系统都支持mmap,于是查看内核支持的文件系统源码,发现都支持。在网上查资料得知下面一段话:

对于二进制,函数将加载一个“a.out”可执行文件并以使用 mmap()加载磁盘文件或调用 read_exec()而结束。前一种方法使用了 Linux的按需加载机理,在程序被访问时使用出错加载方式(fault-in)加载程序页面,而后一种方式是在主机文件系统不支持内存映像时(例如“msdos”文件系统)使用的。从1.1版本内核开始内嵌了一个修订的 msdos 文件系统,它支持 mmap()。而且linux_binfmt 结构已是一个链表而不是一个数组了,以允许以一个内核模块的方式加载一个新的二进制格式。最后,结构的本身也已经被扩展成能够访问与格式相关的核心转储程序了。

        于是下载查看1.0版本的内核中关于msdos文件系统的源码,发现当时的msdos文件系统确实不支持mmap机制,其file结构的操作函数中的mmap函数为空,但其i节点操作函数居然有bmap函数?!好吧,关于具体文件系统为什么不支持mmap的根本原因我分析错了。

        通过比较1.0和1.2中fs/msdos目录下的文件可看出,1.2增加了一个mmap.c,提供了对msdos的mmap的支持。以后再研究吧。

        通过今天的研究理解,对用户层的mmap机制也理解了,就是将要操作的文件映射到进程的地址空间,然后访问文件就想访问内存一样了,只是访问的外在形式方便了,但还是需要按需加载的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值