天天看点

mm_struct

一个进程的虚拟地址空间主要由两个数据结来描述。一个是最高层次的:mm_struct,一个是较高层次的:vm_area_structs。最高层次的mm_struct结构描述了一个进程的整个虚拟地址空间。较高层次的结构vm_area_truct描述了虚拟地址空间的一个区间(简称虚拟区)。每个进程只有一个mm_struct结构,在每个进程的task_struct结构中,有一个指向该进程的结构。可以说,mm_struct结构是对整个用户空间的描述。

  mm_strcut 用来描述一个进程的虚拟地址空间,在/include/linux/sched.h 中描述如下:

struct mm_struct {

  struct vm_area_struct * mmap; /* 指向虚拟区间(VMA)链表 */

  rb_root_t mm_rb; /*指向red_black树*/

  struct vm_area_struct * mmap_cache; /* 指向最近找到的虚拟区间*/

  pgd_t * pgd; /*指向进程的页目录*/ 

  atomic_t mm_users; /* 用户空间中的有多少用户*/

  atomic_t mm_count; /* 对"struct mm_struct"有多少引用*/

  int map_count; /* 虚拟区间的个数*/

  struct rw_semaphore mmap_sem;

  spinlock_t page_table_lock; /* 保护任务页表和 mm->rss */

  struct list_head mmlist; /*所有活动(active)mm的链表 */

  unsigned long start_code, end_code, start_data, end_data; /*start_code 代码段起始地址,end_code 代码段结束地址,start_data 数据段起始地址, start_end 数据段结束地址*/

  unsigned long start_brk, brk, start_stack; /*start_brk 和brk记录有关堆的信息, start_brk是用户虚拟地址空间初始化时,堆的结束地址, brk 是当前堆的结束地址, start_stack 是栈的起始地址*/

  unsigned long arg_start, arg_end, env_start, env_end; /*arg_start 参数段的起始地址, arg_end 参数段的结束地址, env_start 环境段的起始地址, env_end 环境段的结束地址*/

  unsigned long rss, total_vm, locked_vm;

  unsigned long def_flags;

  unsigned long cpu_vm_mask;

  unsigned long swap_address;

  unsigned dumpable:1;

  mm_context_t context; /* Architecture-specific MM context, 是与平台相关的一个结构,对i386 几乎用处不大*/

};

  下面是通过程序打印出来的MM_STRUCT的样例:

 取自Memory Management structure的相关信息 针对如下任务 'cat' (pid=31334)

pgd=D2862000 mmap=D28CFAC4 map_count=17 mm_users=1 mm_count=1

start_code=08048000 end_code=0804C7B4

start_data=0804D7B4 end_data=0804DE40

start_brk=0804E000 brk=0806F000

arg_start=BFCD1973 arg_end=BFCD1980

env_start=BFCD1980 env_end=BFCD1FF3

start_stack=BFCD14E0 down_to=BFCBC4E0

<a href="http://blog.163.com/tianhail@126/blog/static/140395915201031944326379/">http://blog.163.com/tianhail@126/blog/static/140395915201031944326379/</a>

 Linux内核中,关于虚存管理的最基本的管理单元应该是struct vm_area_struct了,它描述的是一段连续的、具有相同访问属性的虚存空间,该虚存空间的大小为物理内存页面的整数倍。

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

QUOTE:

/*

* This struct defines a memory VMM memory area. There is one of these

* per VM-area/task. A VM area is any part of the process virtual memory

* space that has a special rule for the page-fault handlers (ie a shared

* library, the executable area etc).

*/

struct vm_area_struct {

struct mm_struct * vm_mm; /* VM area parameters */

unsigned long vm_start;

unsigned long vm_end;

/* linked list of VM areas per task, sorted by address */

struct vm_area_struct *vm_next;

pgprot_t vm_page_prot;

unsigned long vm_flags;

/* AVL tree of VM areas per task, sorted by address */

short vm_avl_height;

struct vm_area_struct * vm_avl_left;

struct vm_area_struct * vm_avl_right;

/* For areas with an address space and backing store,

* one of the address_space-&gt;i_mmap{,shared} lists,

* for shm areas, the list of attaches, otherwise unused.

struct vm_area_struct *vm_next_share;

struct vm_area_struct **vm_pprev_share;

struct vm_operations_struct * vm_ops;

unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */

struct file * vm_file;

unsigned long vm_raend;

void * vm_private_data; /* was vm_pte (shared mem) */

  vm_area_struct结构所描述的虚存空间以 vm_start、vm_end成员表示,它们分别保存了该虚存空间的首地址和末地址后第一个字节的地址,以字节为单位,所以虚存空间范围可以用 [vm_start, vm_end)表示。

  通常,进程所使用到的虚存空间不连续,且各部分虚存空间的访问属性也可能不同。所以一个进程的虚存空间需要多个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文件里面的文件偏移,单位为物理页面。

  一个程序可以选择MAP_SHARED或MAP_PRIVATE共享模式将一个文件的某部分数据映射到自己的虚存空间里面。这两种映射方式的区别在于:MAP_SHARED映射后在内存中对该虚存空间的数据进行修改会影响到其他以同样方式映射该部分数据的进程,并且该修改还会被写回文件里面去,也就是这些进程实际上是在共用这些数据。而MAP_PRIVATE映射后对该虚存空间的数据进行修改不会影响到其他进程,也不会被写入文件中。

  来自不同进程,所有映射同一个文件的vm_area_struct结构都会根据其共享模式分别组织成两个链表。链表的链头分别是:vm_file-&gt;f_dentry-&gt;d_inode-&gt;i_mapping-&gt;i_mmap_shared, vm_file-&gt;f_dentry-&gt;d_inode-&gt;i_mapping-&gt;i_mmap。而 vm_area_struct结构中的vm_next_share指向链表中的下一个节点;vm_pprev_share是一个指针的指针,它的值是链表中上一个节点(头节点)结构的vm_next_share(i_mmap_shared或i_mmap)的地址。

  进程建立vm_area_struct结构后,只是说明进程可以访问这个虚存空间,但有可能还没有分配相应的物理页面并建立好页面映射。在这种情况下,若是进程执行中有指令需要访问该虚存空间中的内存,便会产生一次缺页异常。这时候,就需要通过vm_area_struct结构里面的 vm_ops-&gt;nopage所指向的函数来将产生缺页异常的地址对应的文件数据读取出来。

  vm_flags主要保存了进程对该虚存空间的访问权限,然后还有一些其他的属性。vm_page_prot是新映射的物理页面的页表项pgprot 的默认值。

<a href="http://www.deansys.com/doc/ldd3/ch15.html">http://www.deansys.com/doc/ldd3/ch15.html</a>

继续阅读