linux 页表
简单来说,讨论linux页表就是讨论linux进程的的页表:linux页表的创建与更新都包含于进程的创建与更新中。当前的linux内核采用的是写时复制方法,在创建一个linux进程时,完全复制父进程的页表,并且将父子进程的页表均置为写保护(即写地址的时候会产生缺页异常等)。那么父子进程谁向地址空间写数据时,产生缺页异常,分配新的页,并将两个页均置为可写,按照这种方式父子进程的地址空间渐渐变得不同(也即页表变得不同)。 按照上面的分析, 只需要讨论第一个进程页表初始化,进程创建时页表的拷贝,以及缺页异常时页表的更新即可。 1.init_task进程页表的初始化 init_task的地址空间是init_mm, init_mm在内核初始化的时候就赋值给了current->active_mm. init_mm的初始化页表是swapper_pg_dir,在mips架构中swapper_pg_dir初始化在函数pagetable_init中,初始化关系是 swapper_pg_dir -> invalide_pmd_table -> invalide_pte_table 或 swapper_pg_dir -> invalide_pte_table. 即在init_mm中,页表指向的全部是invalide_pte_table。 2.创建进程时页表的拷贝 进程创建一般调用的是do_fork函数,按照如下调用关系: do_fork->copy_process->copy_mm->dup_mm->dup_mmap->copy_page_range 找到copy_page_range函数,这个函数便是负责页表的拷贝,函数核心代码如下: 874 do { 875 next = pgd_addr_end(addr, end); 876 if (pgd_none_or_clear_bad(src_pgd)) 877 continue; 878 if (unlikely(copy_pud_range(dst_mm, src_mm, dst_pgd, src_pgd, 879 vma, addr, next))) { 880 ret = -ENOMEM; 881 br...