与进程地址空间有关的全部信息都包含在一个叫做内存描述符(memory descriptor)的数据结构中(实际上就是描述进程虚拟内存的数据结构),这个结构的类型为mm_struct,进程描述符的mm字段就指向这个结构。
struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */ //指向线性区对象的链表头
struct rb_root mm_rb; //指向线性区对象的红-黑树的根
struct vm_area_struct * mmap_cache; /* last find_vma result */ //指向最后一个引用线性区对象
unsigned long (*get_unmapped_area) (struct file *filp, //在进程地址空间中搜索有效线性地址区间的方法
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);
void (*unmap_area) (struct vm_area_struct *area); //释放线性地址区间时调用的方法
unsigned long mmap_base; /* base of mmap area */ //标志第一个分配的匿名线性区或文件内
unsigned long free_area_cache; /* first hole */ //内核从这个地址开始搜索进程地址空间中线性地址的空闲区间
pgd_t * pgd; //指向页全局目录
atomic_t mm_users; /* How many users with user space? */ //次使用计数器
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ //主使用计数器
int map_count; /* number of VMAs */ //线性区的个数
struct rw_semaphore mmap_sem; //线性区的读写信号量
spinlock_t page_table_lock; /* Protects page tables, mm->rss, mm->anon_rss */ //线性区的自旋锁和页表的自旋锁
struct list_head mmlist; /* List of maybe swapped mm‘s. These are globally strung //指向内存描述符链表中的相邻元素
* together off init_mm.mmlist, and are protected
* by mmlist_lock
*/
unsigned long start_code, //可执行代码的起始地址
end_code, //可执行代码的最后地址
start_data, //已初始化数据的起始地址
end_data; //已初始化数据的最后地址
unsigned long start_brk, //堆的起始地址
brk, //堆的当前最后地址
start_stack;//用户态堆栈的起始地址
unsigned long arg_start, //命令行参数起始地址
arg_end, //命令行参数最后地址
env_start, //环境变量的起始地址
env_end; //环境变量的最后地址
unsigned long rss, //分配给进程的页框数
anon_rss, //分配给匿名内存映射的页框数
total_vm, //进程地址空间的大小
locked_vm, //“锁住”而不能换出的页的个数
shared_vm; //共享文件内存映射中的页数
unsigned long exec_vm, //可执行内存映射中的页数
stack_vm, //用户态堆栈中的页数
reserved_vm,//在保留区中的页数
def_flags, //线性区默认的访问标志
nr_ptes; //this进程的页表数
unsigned long saved_auxv[42]; /* for /proc/PID/auxv */ //开始执行ELF程序是使用
entry = *pte;
if (!pte_present(entry)) {
/*
* If it truly wasn‘t present, we know that kswapd
* and the PTE updates will not touch it later. So
* drop the lock.
*/
if (pte_none(entry))
return do_no_page(mm, vma, address, write_access, pte, pmd);
if (pte_file(entry))
return do_file_page(mm, vma, address, write_access, pte, pmd);
return do_swap_page(mm, vma, address, pte, pmd, entry, write_access);
}
if (write_access) {
if (!pte_write(entry))
return do_wp_page(mm, vma, address, pte, pmd, entry);