免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6494 | 回复: 7
打印 上一主题 下一主题

copy_mm流程解析,顺便问两个问题。。没看太懂。。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-06-05 15:28 |只看该作者 |倒序浏览
本帖最后由 cluter 于 2011-06-05 15:32 编辑

只讲大体流程,不过分追究细节了,因为细节我也没全搞懂,所以只能先整体上把握了。。。 希望大牛指正!
  1. //******************************copy_mm**********************************************
  2. static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
  3. {

  4.         // 1 如果内存空间共享,直接增加内存描述符mm的引用计数,然后退出
  5.         if (clone_flags & CLONE_VM) {
  6.                 atomic_inc(&oldmm->mm_users);
  7.                 mm = oldmm;
  8.                 goto good_mm;
  9.         }

  10.         // 2 如果内存空间不共享,则创建一个新的内存空间
  11.         mm = dup_mm(tsk);


  12. good_mm:

  13.         // 3 对于进程来说mm和active_mm指向同一内存描述符mm
  14.         //   对于内核线程来说,使用active_mm指向当前进程的内存描述符mm
  15.         //   内核线程不使用线性区
  16.         tsk->mm = mm;
  17.         tsk->active_mm = mm;
  18.         return 0;

  19. }



  20. struct mm_struct *dup_mm(struct task_struct *tsk)
  21. {

  22.         // 1 为新进程分配一个新的内存描述符mm
  23.         mm = allocate_mm();


  24.         // 2 先拷贝父进程内存描述符的所有内容
  25.         memcpy(mm, oldmm, sizeof(*mm));


  26.         // 3 初始化新内存描述符mm中的字段(包括为新进程分配一个新的pgd)
  27.         if (!mm_init(mm, tsk))
  28.                 goto fail_nomem;


  29.         // 4 复制父进程的线性区间和页表
  30.         err = dup_mmap(mm, oldmm);

  31. }



  32. // 1 分配新的vma线性区并初始化
  33. // 2 如果vma线性区是file 映射则加入priority-search tree
  34. // 3 把新的vma线性区加入内存描述符mm的red-black tree
  35. // 4 链接vma线性区间
  36. // 5 复制页表项
  37. static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
  38. {
  39.         struct vm_area_struct *mpnt, *tmp, *prev, **pprev;
  40.         struct rb_node **rb_link, *rb_parent;
  41.         int retval;
  42.         unsigned long charge;
  43.         struct mempolicy *pol;

  44.         //获取锁
  45.         down_write(&oldmm->mmap_sem);
  46.         flush_cache_dup_mm(oldmm);
  47.         /*
  48.          * Not linked in yet - no deadlock potential:
  49.          */
  50.         down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);

  51.         //初始化mm描述符
  52.         mm->locked_vm = 0;
  53.         mm->mmap = NULL;
  54.         mm->mmap_cache = NULL;
  55.         mm->free_area_cache = oldmm->mmap_base;
  56.         mm->cached_hole_size = ~0UL;
  57.         mm->map_count = 0;
  58.         cpumask_clear(mm_cpumask(mm));
  59.         mm->mm_rb = RB_ROOT;
  60.         rb_link = &mm->mm_rb.rb_node;
  61.         rb_parent = NULL;
  62.         pprev = &mm->mmap;
  63.         retval = ksm_fork(mm, oldmm);
  64.         if (retval)
  65.                 goto out;

  66.         prev = NULL;
  67.         //开始复制vma线性区
  68.         for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) {
  69.                 struct file *file;

  70.                 //线性区间不允许拷贝
  71.                 if (mpnt->vm_flags & VM_DONTCOPY) {
  72.                         long pages = vma_pages(mpnt);
  73.                         //那么进程地址空间大小就要减去该线性区间
  74.                         mm->total_vm -= pages;
  75.                         vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,
  76.                                                                 -pages);
  77.                         continue;
  78.                 }
  79.                 charge = 0;
  80.                 //IPC共享线性区,检查是否有足够的内存用于映射
  81.                 if (mpnt->vm_flags & VM_ACCOUNT) {
  82.                         unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
  83.                         if (security_vm_enough_memory(len))
  84.                                 goto fail_nomem;
  85.                         charge = len;
  86.                 }
  87.                 //分配一个新的vma线性区
  88.                 tmp = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
  89.                 if (!tmp)
  90.                         goto fail_nomem;
  91.                 //复制内容
  92.                 *tmp = *mpnt;
  93.                 INIT_LIST_HEAD(&tmp->anon_vma_chain);
  94.                 pol = mpol_dup(vma_policy(mpnt));
  95.                 retval = PTR_ERR(pol);
  96.                 if (IS_ERR(pol))
  97.                         goto fail_nomem_policy;
  98.                 vma_set_policy(tmp, pol);
  99.                 if (anon_vma_fork(tmp, mpnt))
  100.                         goto fail_nomem_anon_vma_fork;
  101.                 tmp->vm_flags &= ~VM_LOCKED;
  102.                 tmp->vm_mm = mm;
  103.                 tmp->vm_next = tmp->vm_prev = NULL;
  104.                 file = tmp->vm_file;
  105.                 //该vma线性区是否是文件映射
  106.                 if (file) {
  107.                         //获取该文件映射对应的address_space
  108.                         struct inode *inode = file->f_path.dentry->d_inode;
  109.                         struct address_space *mapping = file->f_mapping;

  110.                         get_file(file);
  111.                         if (tmp->vm_flags & VM_DENYWRITE)
  112.                                 atomic_dec(&inode->i_writecount);
  113.                         spin_lock(&mapping->i_mmap_lock);
  114.                         if (tmp->vm_flags & VM_SHARED)
  115.                                 mapping->i_mmap_writable++;
  116.                         tmp->vm_truncate_count = mpnt->vm_truncate_count;
  117.                         flush_dcache_mmap_lock(mapping);
  118.                         /* insert tmp into the share list, just after mpnt */
  119.                         //新的vma线性区直接插入priority-search tree
  120.                         //priority-search tree主要用于页框回收时,释放所有映射该页框的页表项
  121.                         vma_prio_tree_add(tmp, mpnt);
  122.                         flush_dcache_mmap_unlock(mapping);
  123.                         spin_unlock(&mapping->i_mmap_lock);
  124.                 }

  125.                 /*
  126.                  * Clear hugetlb-related page reserves for children. This only
  127.                  * affects MAP_PRIVATE mappings. Faults generated by the child
  128.                  * are not guaranteed to succeed, even if read-only
  129.                  */
  130.                 if (is_vm_hugetlb_page(tmp))
  131.                         reset_vma_resv_huge_pages(tmp);

  132.                 /*
  133.                  * Link in the new vma and copy the page table entries.
  134.                  */
  135.                  //把刚分配的vma线性区链接起来
  136.                 *pprev = tmp;
  137.                 pprev = &tmp->vm_next;
  138.                 tmp->vm_prev = prev;
  139.                 prev = tmp;
  140.                 //把新分配的vma线性区插入red-black tree
  141.                 __vma_link_rb(mm, tmp, rb_link, rb_parent);
  142.                 rb_link = &tmp->vm_rb.rb_right;
  143.                 rb_parent = &tmp->vm_rb;

  144.                 mm->map_count++;
  145.                 //拷贝页表项
  146.                 retval = copy_page_range(mm, oldmm, mpnt);

  147.                 if (tmp->vm_ops && tmp->vm_ops->open)
  148.                         tmp->vm_ops->open(tmp);

  149.                 if (retval)
  150.                         goto out;
  151.         }
  152.         /* a new mm has just been created */
  153.         arch_dup_mmap(oldmm, mm);
  154.         retval = 0;
  155. out:
  156.         up_write(&mm->mmap_sem);
  157.         flush_tlb_mm(oldmm);
  158.         up_write(&oldmm->mmap_sem);
  159.         return retval;
  160. fail_nomem_anon_vma_fork:
  161.         mpol_put(pol);
  162. fail_nomem_policy:
  163.         kmem_cache_free(vm_area_cachep, tmp);
  164. fail_nomem:
  165.         retval = -ENOMEM;
  166.         vm_unacct_memory(charge);
  167.         goto out;
  168. }



  169. //************copy_page_range**********************

  170. //调用流程
  171. copy_page_range
  172.         |
  173.         |
  174.         |
  175. copy_pud_range
  176.         |
  177.         |
  178.         |
  179. copy_pmd_range
  180.               |
  181.               |
  182.         |
  183. copy_pte_range
  184.         |
  185.         |
  186.         |
  187. copy_one_pte


  188. //对于copy_one_pte有两个重要的地方

  189. // 最开始是关于如果页表所映射的页框已经在swap中的处理过程

  190. // 1 如果是copy on write映射,则父子页表都要写保护
  191.         /*
  192.          * If it's a COW mapping, write protect it both
  193.          * in the parent and the child
  194.          */
  195.         if (is_cow_mapping(vm_flags)) {
  196.                 ptep_set_wrprotect(src_mm, addr, src_pte);
  197.                 pte = pte_wrprotect(pte);
  198.         }


  199. // 2 如果是共享映射 ,则清空子进程页表项,属于请求调页
  200.      [size=7][color=Magenta]  //如果是共享映射,为啥不直接负责页表项,而是清空子进程页表项?[/color][/size]

  201.         /*
  202.          * If it's a shared mapping, mark it clean in
  203.          * the child
  204.          */
  205.         if (vm_flags & VM_SHARED)
  206.                 pte = pte_mkclean(pte);
  207.         pte = pte_mkold(pte);[color=Red][size=7]------>这里标记页表被访问过是啥意思?[/size][/color]

复制代码

评分

参与人数 1可用积分 +8 收起 理由
Godbach + 8 感谢分享

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2011-06-05 15:31 |只看该作者
// 2 如果是共享映射 ,则清空子进程页表项,属于请求调页
       //如果是共享映射,为啥不直接复制页表项,而是清空子进程页表项?

        /*
         * If it's a shared mapping, mark it clean in
         * the child
         */
        if (vm_flags & VM_SHARED)
                pte = pte_mkclean(pte);
        pte = pte_mkold(pte);------>这里标记页表被访问过是啥意思?

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2011-06-05 16:42 |只看该作者
pte_mkclean/pte_mkold都是修正父进程的pte,然后拷贝到子进程的页表中,你的理解没错.
mkclean不等于清空

论坛徽章:
0
4 [报告]
发表于 2011-06-08 09:26 |只看该作者
本帖最后由 懂医术的厨师 于 2011-06-08 09:27 编辑

1. copy_mm一开始就判断是否CLONE_VM,如果是则加一。否则拷贝,直到copy_page_range,此时以明确不再share,如果发现share,则清空子进程的pte
2.清空pte并不是暴力删除这个条目,可能以后还会用呢,所以直接mark为clean就行了,lazy work

论坛徽章:
0
5 [报告]
发表于 2011-06-08 11:59 |只看该作者
谢谢楼上2位。。。

论坛徽章:
0
6 [报告]
发表于 2011-06-08 12:00 |只看该作者
回复 4# 懂医术的厨师


    mkold是标记页表项已经被访问过?这个用意何在?和页框回收有关系?

论坛徽章:
0
7 [报告]
发表于 2011-06-08 12:11 |只看该作者
回复 6# cluter

和tlb,proc统计等有关,简单贴段:
int ptep_clear_flush_young(struct vm_area_struct *vma,
{
    young = ptep_test_and_clear_young(vma, address, ptep);
    if (young)
      flush_tlb_page(vma, address);
...

论坛徽章:
0
8 [报告]
发表于 2011-06-08 21:30 |只看该作者
回复 7# 懂医术的厨师


    谢谢LS解答。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP