Linux -----mmap进行内存映射的原理(未完成)

原创 2016年08月29日 00:22:07

     mmap系统调用的最终目的是将,设备或文件映射到用户进程的虚拟地址空间,实现用户进程对文件的直接读写,这个任务可以分为以下三步:

1.在用户虚拟地址空间中寻找空闲的满足要求的一段连续的虚拟地址空间,为映射做准备(由内核mmap系统调用完成)

       每个进程拥有3G字节的用户虚存空间。但是,这并不意味着用户进程在这3G的范围内可以任意使用,因为虚存空间最终得映射到某个物理存储空间(内存或磁盘空间),才真正可以使用。

       那么,内核怎样管理每个进程3G的虚存空间呢?概括地说,用户进程经过编译、链接后形成的映象文件有一个代码段和数据段(包括data段和bss段),其中代码段在下,数据段在上。数据段中包括了所有静态分配的数据空间,即全局变量和所有申明为static的局部变量,这些空间是进程所必需的基本要求,这些空间是在建立一个进程的运行映像时就分配好的。除此之外,堆栈使用的空间也属于基本要求,所以也是在建立进程时就分配好的,如图3.1所示:

 

 

 图3.1  进程虚拟空间的划分

      在内核中,这样每个区域用一个结构struct vm_area_struct 来表示.它描述的是一段连续的、具有相同访问属性的虚存空间,该虚存空间的大小为物理内存页面的整数倍。可以使用 cat /proc//maps来查看一个进程的内存使用情况,pid是进程号.其中显示的每一行对应进程的一个vm_area_struct结构.

下面是struct vm_area_struct结构体的定义:

  1. #include <linux/mm_types.h>

  2. /* This struct defines a memory VMM memory area. */

  3. struct vm_area_struct {
  4. struct mm_struct * vm_mm; /* VM area parameters */
  5. unsigned long vm_start;
  6. unsigned long vm_end;

  7. /* linked list of VM areas per task, sorted by address */
  8. struct vm_area_struct *vm_next;
  9. pgprot_t vm_page_prot;
  10. unsigned long vm_flags;

  11. /* AVL tree of VM areas per task, sorted by address */
  12. short vm_avl_height;
  13. struct vm_area_struct * vm_avl_left;
  14. struct vm_area_struct * vm_avl_right;

  15. /* For areas with an address space and backing store,
  16. vm_area_struct *vm_next_share;
  17. struct vm_area_struct **vm_pprev_share;
  18. struct vm_operations_struct * vm_ops;
  19. unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
  20. struct file * vm_file;
  21. unsigned long vm_raend;
  22. void * vm_private_data; /* was vm_pte (shared mem) */
  23. };

      通常,进程所使用到的虚存空间不连续,且各部分虚存空间的访问属性也可能不同。所以一个进程的虚存空间需要多个vm_area_struct结构来描述。在vm_area_struct结构的数目较少的时候,各个vm_area_struct按照升序排序,以单链表的形式组织数据(通过vm_next指针指向下一个vm_area_struct结构)。但是当vm_area_struct结构的数据较多的时候,仍然采用链表组织的化,势必会影响到它的搜索速度。针对这个问题,vm_area_struct还添加了vm_avl_hight(树高)、vm_avl_left(左子节点)、vm_avl_right(右子节点)三个成员来实现AVL树,以提高vm_area_struct的搜索速度。

  假如该vm_area_struct描述的是一个文件映射的虚存空间,成员vm_file便指向被映射的文件的file结构,vm_pgoff是该虚存空间起始地址在vm_file文件里面的文件偏移,单位为物理页面。

图3.2  进程虚拟地址示意图 

因此,mmap系统调用所完成的工作就是准备这样一段虚存空间,并建立vm_area_struct结构体,将其传给具体的设备驱动程序.

2. 建立虚拟地址空间和文件或设备的物理地址之间的映射(设备驱动完成)

  建立文件映射的第二步就是建立虚拟地址和具体的物理地址之间的映射,这是通过修改进程页表来实现的.mmap方法是file_opeartions结构的成员:

  int (*mmap)(struct file *,struct vm_area_struct *);


linux有2个方法建立页表:

(1) 使用remap_pfn_range一次建立所有页表.

   int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t prot); 

返回值:

成功返回 0, 失败返回一个负的错误值
参数说明:

vma 用户进程创建一个vma区域


virt_addr 重新映射应当开始的用户虚拟地址. 这个函数建立页表为这个虚拟地址范围从 virt_addr 到 virt_addr_size.


pfn 页帧号, 对应虚拟地址应当被映射的物理地址. 这个页帧号简单地是物理地址右移 PAGE_SHIFT 位. 对大部分使用, VMA 结构的 vm_paoff 成员正好包含你需要的值. 这个函数影响物理地址从 (pfn<<page_shift) 到 (pfn<<page_shift)+size.< span="" style="word-wrap: break-word;">


size 正在被重新映射的区的大小, 以字节.


prot 给新 VMA 要求的"protection". 驱动可(并且应当)使用在vma->vm_page_prot 中找到的值.

(2) 使用nopage VMA方法每次建立一个页表项.

   struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address, int *type);

返回值:

成功则返回一个有效映射页,失败返回NULL.

参数说明:

address 代表从用户空间传过来的用户空间虚拟地址.

返回一个有效映射页.


(3) 使用方面的限制:

remap_pfn_range不能映射常规内存,只存取保留页和在物理内存顶之上的物理地址。因为保留页和在物理内存顶之上的物理地址内存管理系统的各个子模块管理不到。640 KB 和 1MB 是保留页可能映射,设备I/O内存也可以映射。如果想把kmalloc()申请的内存映射到用户空间,则可以通过mem_map_reserve()把相应的内存设置为保留后就可以。

Linux的mmap内存映射机制解析

在讲述文件映射的概念时, 不可避免的要牵涉到虚存(SVR 4的VM). 实际上, 文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施, 好似用户将文件映射到自己地址空间的某个部分, 使用...
  • zqixiao_09
  • zqixiao_09
  • 2016年04月07日 19:48
  • 8588

Linux内核源码阅读之内存映射篇

Linux内核内存映射包括创建虚拟区间地址和改变映射区域的边界地址两部分。首先先来看创建虚拟区间地址部分,本部分代码主要在linux-2.6.33.2/mm下的mmap.c中,通过系统调用mmap可以...
  • f413933206
  • f413933206
  • 2010年06月29日 14:58
  • 4745

在linux中使用内存映射(mmap)操作文件

在使用内存映射操作文件之前,我们先按照常规的方式来读写文件,这种方式操作如下: 1,打开或创建文件,得到文件描述符, 2,将内存中的数据以一定的格式和顺序写入文件,或者将文件中的数据以一定的格式和顺序...
  • hulele2009
  • hulele2009
  • 2013年11月15日 16:50
  • 9040

Linux进程间通信(一):管道与mmap文件-内存映射

一、无名管道、有名管道与进程间通信:1、IPC–进程间通信与管道基本概念:(1)、IPC(进程间通信):所谓IPC就是两个或者多个进程之间的数据交互(在不能直接进行信息交互的两个进程间增加一个“交互媒...
  • Apollon_krj
  • Apollon_krj
  • 2017年02月17日 01:09
  • 683

在linux中使用内存映射(mmap)操作文件的方法

在使用内存映射操作文件之前,我们先按照常规的方式来读写文件,这种方式操作如下: 1,打开或创建文件,得到文件描述符, 2,将内存中的数据以一定的格式和顺序写入文件,或者将文件中的数据以一定的格式和...
  • bzhxuexi
  • bzhxuexi
  • 2015年06月04日 15:22
  • 688

Linux驱动mmap内存映射

mmap
  • chenshengfa
  • chenshengfa
  • 2016年01月14日 19:50
  • 3113

Unix/Linux的 mmap()内存映射

mmap() UNIX网络编程第二卷进程间通信对mmap函数进行了说明。该函数主要用途有三个: 1、将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写...
  • sunny04
  • sunny04
  • 2015年06月09日 15:07
  • 756

mmap映射区和shm共享内存的区别总结

linux中的两种共享内存。一种是我们的IPC通信System V版本的共享内存,另外的一种就是我们今天提到的存储映射I/O(mmap函数) 在说mmap之前我们先说一下普通的读写文件的原理,进...
  • hj605635529
  • hj605635529
  • 2017年06月13日 11:45
  • 1894

文件内存映射mmap解决大文件快速读写问题

转自:http://blog.csdn.net/gulaizi/article/details/6325726 mmap函数主要用途有三个: 1、将一个普通文件映射到内存中,通常在需要对文...
  • missingu1314
  • missingu1314
  • 2013年05月16日 12:11
  • 1663

计算机底层知识拾遗(九)深入理解内存映射mmap

内存映射mmap是Linux内核的一个重要机制,它和虚拟内存管理以及文件IO都有直接的关系,这篇细说一下mmap的一些要点。 mmap和虚拟内存管理 先来看看Linux内核的用户进程虚拟内存管...
  • ITer_ZC
  • ITer_ZC
  • 2015年03月16日 17:08
  • 4629
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux -----mmap进行内存映射的原理(未完成)
举报原因:
原因补充:

(最多只允许输入30个字)