设为首页 加入收藏

TOP

巨页的原理分析(一)
2013-07-23 09:10:32 来源: 作者: 【 】 浏览:464
Tags:原理 分析

 

  再接着往下看,如果是第一次访问巨页空间,那么走的是hugetlb_no_page,这是个相对较大的函数。

  [cpp]

  static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,

  unsigned long address, pte_t *ptep, unsigned int flags)

  {

  idx = vma_hugecache_offset(h, vma, address);

  page = find_lock_page(mapping, idx);

  if (!page) {

  size = i_size_read(mapping->host) >> huge_page_shift(h);

  page = alloc_huge_page(vma, address, 0);

  err = add_to_page_cache(page, mapping, idx, GFP_KERNEL);

  }

  new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)

  && (vma->vm_flags & VM_SHARED)));

  set_huge_pte_at(mm, address, ptep, new_pte);

  }

  hugetlb_no_page负责分配一块连续的页框,根据一个巨页所包含的虚拟空间,将所有涉及到的页表项pte entry,都指向这块连续页框的起始地址。这样,以后无论进程发生在这块巨页空间里任何一处的tlb异常,都会将tlb的pfn指向这块物理空间,保证完成最终的tlb映射。

  vma_hugecache_offset根据传入的缺页地址address,计算出此address相对于整个地址空间的index(以巨页大小为单位)

  接着,根据idx在mapping空间里找出对应的page, 即巨页的第一个页。如果找到不对应的页,则说明还没有分配巨页,于是调用

  alloc_huge_page,要么从hstates高速缓冲,要么从伙伴系统获取物理连续的页框,之后通过

  add_to_page_cache加到page cache里,可以看出,巨页文件对应的mapping,都是由巨页的index构成的radix tree。

  紧接着,根据找到的page,生成一个pte entry,并给pte entry设置上_PAGE_HUGE标记,以便在缺页返回后,再次访址引起的tlb load异常时,可以

  辨识出这是一个巨页pte entry。

  最后,set_huge_pte_at(mm,address,ptep,new_pte)是比较关键的地方。

  [cpp]

  void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,

  pte_t entry)

  {

  unsigned long i;

  unsigned long htlb_entries = 1 << HUGETLB_PAGE_ORDER;

  pte_t entry2;

  entry2 = __pte(pte_val(entry) + (HPAGE_SIZE >> 1));

  addr &= HPAGE_MASK;

  for (i = 0; i < htlb_entries; i += 2) {

  ptep = huge_pte_offset(mm, addr);

  set_pte_at(mm, addr, ptep, entry);

  addr += PAGE_SIZE;

  ptep = huge_pte_offset(mm, addr);

  set_pte_at(mm, addr, ptep, entry2);

  addr += PAGE_SIZE;

  }

  }

  这个函数,首先计算出一个巨页需要htlb_entries个连续页框,接着,根据hugetlb奇数页,加上一个巨页一半大小,算出偶数页所在的tlb entry2。

  接着,对addr到addr+HPAGE_SIZE的空间内,凡是奇数页地址,都设置为entry,而偶数页则都设置为entry2,示意图如下:


  在 page fault返回后,再次访址将产生tlb load/store异常。在build_r4000_tlbchange_handler_head函数里,

  经过一系列页表寻址,找到pte entry条目,由于这个条目之前在hugetlb_no_page已经被设置了_PAGE_HUGE,

  因此会走tlb_huge_update-->build_huge_handler_tail-->build_huge_update_entries将获取到的奇偶页表项,

  写入entrylo1 和 entrylo 2。

  [cpp]

  static __cpuinit void build_huge_update_entries(u32 **p,

  unsigned int pte,

  unsigned int tmp)

  {

  build_convert_pte_to_entrylo(p, pte);

  UASM_i_MTC0(p, pte, C0_ENTRYLO0); /* load it */

  uasm_i_ld(p, pte, sizeof(pte_t), tmp);

  build_convert_pte_to_entrylo(p, pte);

  UASM_i_MTC0(p, pte, C0_ENTRYLO1); /* load it */

  uasm_i_ehb(p);

  }

  其中,uasm_i_ld(p,pte,sizeof(pte_t),tmp) 将传入的奇数页pte entry指针,加上一个pte_t的长度,取地址内容,得到偶数页pte entry的值接着通过build_huge_tlb_write_entry(p, l, r, pte, tlb_random);将奇偶数页都写入TLB条目。(因为此时系统中没有匹配虚拟地址的tlb条目,所以probe失败,index小于0,会跳过build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed);

          

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C++ 内连接与外连接 下一篇引用计数的智能指针shared_ptr

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: