免费注册 查看新帖 |

Chinaunix

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

[内核入门] 关于线性区合并函数vma_merge中case4的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-05-19 17:36 |只看该作者 |倒序浏览
case4的情况是当新的线性区不能与前面合并,但可以与后面合并,且新线性区的开始地址add < prev->vm_end,如下图:

这里case4合并后,按意思来理解,应该是将prev缩减x,然后next与new_area合并,但是vma_adjust实际代码却只是将next的空间向前扩展x,而不是到new_vm_area的vm_start(addr)
vma_merge
mm/mmap.c(linux kernel 2.6.11.7)
代码如下:

  1. struct vm_area_struct *vma_merge(struct mm_struct *mm,
  2.                         struct vm_area_struct *prev, unsigned long addr,
  3.                         unsigned long end, unsigned long vm_flags,
  4.                         struct anon_vma *anon_vma, struct file *file,
  5.                         pgoff_t pgoff, struct mempolicy *policy)
  6. {
  7.          pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
  8.          struct vm_area_struct *area, *next;

  9. if (vm_flags & VM_SPECIAL)
  10.                  return NULL;

  11.          if (prev)
  12.                  next = prev->vm_next;
  13.          else
  14.                  next = mm->mmap;
  15.          area = next;
  16.          if (next && next->vm_end == end)                /* cases 6, 7, 8 */
  17.                  next = next->vm_next;
  18.         if (prev && prev->vm_end == addr &&
  19.                        mpol_equal(vma_policy(prev), policy) &&
  20.                         can_vma_merge_after(prev, vm_flags,
  21.                                              anon_vma, file, pgoff)) {
  22.               
  23.                 if (next && end == next->vm_start &&
  24.                                 mpol_equal(policy, vma_policy(next)) &&
  25.                                can_vma_merge_before(next, vm_flags,
  26.                                         anon_vma, file, pgoff+pglen) &&
  27.                                 is_mergeable_anon_vma(prev->anon_vma,
  28.                                                       next->anon_vma)) {
  29.                          /* cases 1, 6 */
  30.                         vma_adjust(prev, prev->vm_start,
  31.                                 next->vm_end, prev->vm_pgoff, NULL);
  32.                } else                                  /* cases 2, 5, 7 */
  33.                        vma_adjust(prev, prev->vm_start,
  34.                                 end, prev->vm_pgoff, NULL);
  35.                 return prev;
  36.         }

  37.                if (next && end == next->vm_start &&
  38.                         mpol_equal(policy, vma_policy(next)) &&
  39.                         can_vma_merge_before(next, vm_flags,
  40.                                         anon_vma, file, pgoff+pglen)) {
  41.                if (prev && addr < prev->vm_end)        /* case 4 */
  42.                         vma_adjust(prev, prev->vm_start,
  43.                                 addr, prev->vm_pgoff, NULL);
  44.                 else                                    /* cases 3, 8 */
  45.                         vma_adjust(area, addr, next->vm_end,
  46.                                 next->vm_pgoff - pglen, NULL);
  47.                 return area;
  48.         }

  49.        return NULL;
  50. }
复制代码
vma_adjust
mm/mmap.c(linux kernel 2.6.11.7)
代码如下:

  1. void vma_adjust(struct vm_area_struct *vma, unsigned long start,
  2.         unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert)
  3. {
  4.         struct mm_struct *mm = vma->vm_mm;
  5.         struct vm_area_struct *next = vma->vm_next;
  6.         struct vm_area_struct *importer = NULL;
  7.         struct address_space *mapping = NULL;
  8.         struct prio_tree_root *root = NULL;
  9.         struct file *file = vma->vm_file;
  10.         struct anon_vma *anon_vma = NULL;
  11.         long adjust_next = 0;
  12.         int remove_next = 0;

  13.         /*insert为NULL 查看vma和next合并*/
  14.         if (next && !insert) {
  15.                 if (end >= next->vm_end) {
  16.                         /*
  17.                          * vma expands, overlapping all the next, and
  18.                          * perhaps the one after too (mprotect case 6).
  19.                          */
  20.                         /* case 1,6*/
  21. again:                        remove_next = 1 + (end > next->vm_end);
  22.                         end = next->vm_end;
  23.                         anon_vma = next->anon_vma;
  24.                         importer = vma;
  25.                 } else if (end > next->vm_start) {
  26.                         /*
  27.                          * vma expands, overlapping part of the next:
  28.                          * mprotect case 5 shifting the boundary up.
  29.                          */
  30.                         /*case 5*/
  31.                         adjust_next = (end - next->vm_start) >> PAGE_SHIFT;
  32.                         anon_vma = next->anon_vma;
  33.                         importer = vma;
  34.                 } else if (end < vma->vm_end) {
  35.                         /*
  36.                          * vma shrinks, and !insert tells it's not
  37.                          * split_vma inserting another: so it must be
  38.                          * mprotect case 4 shifting the boundary down.
  39.                          */
  40.                         adjust_next = - ((vma->vm_end - end) >> PAGE_SHIFT); /*case4  就是这里adjust_next*/
  41.                         anon_vma = next->anon_vma;
  42.                         importer = next;
  43.                 }
  44.         }

  45.         if (file) {
  46.                 mapping = file->f_mapping;
  47.                 if (!(vma->vm_flags & VM_NONLINEAR))
  48.                         root = &mapping->i_mmap;
  49.                 spin_lock(&mapping->i_mmap_lock);
  50.                 if (importer &&
  51.                     vma->vm_truncate_count != next->vm_truncate_count) {
  52.                         /*
  53.                          * unmap_mapping_range might be in progress:
  54.                          * ensure that the expanding vma is rescanned.
  55.                          */
  56.                         importer->vm_truncate_count = 0;
  57.                 }
  58.                 if (insert) {
  59.                         insert->vm_truncate_count = vma->vm_truncate_count;
  60.                         /*
  61.                          * Put into prio_tree now, so instantiated pages
  62.                          * are visible to arm/parisc __flush_dcache_page
  63.                          * throughout; but we cannot insert into address
  64.                          * space until vma start or end is updated.
  65.                          */
  66.                         __vma_link_file(insert);
  67.                 }
  68.         }

  69.         /*
  70.          * When changing only vma->vm_end, we don't really need
  71.          * anon_vma lock: but is that case worth optimizing out?
  72.          */
  73.         if (vma->anon_vma)
  74.                 anon_vma = vma->anon_vma;
  75.         if (anon_vma) {
  76.                 spin_lock(&anon_vma->lock);
  77.                 /*
  78.                  * Easily overlooked: when mprotect shifts the boundary,
  79.                  * make sure the expanding vma has anon_vma set if the
  80.                  * shrinking vma had, to cover any anon pages imported.
  81.                  */
  82.                 if (importer && !importer->anon_vma) {
  83.                         importer->anon_vma = anon_vma;
  84.                         __anon_vma_link(importer);
  85.                 }
  86.         }

  87.         if (root) {
  88.                 flush_dcache_mmap_lock(mapping);
  89.                 vma_prio_tree_remove(vma, root);
  90.                 if (adjust_next)
  91.                         vma_prio_tree_remove(next, root);
  92.         }

  93.         vma->vm_start = start;
  94.         vma->vm_end = end;
  95.         vma->vm_pgoff = pgoff;
  96.         if (adjust_next) {  /*case4  就是这里adjust_next调整next->vm_start 仅仅扩展了上图的x而已*/
  97.                 next->vm_start += adjust_next << PAGE_SHIFT;
  98.                 next->vm_pgoff += adjust_next;
  99.         }

  100.         if (root) {
  101.                 if (adjust_next)
  102.                         vma_prio_tree_insert(next, root);
  103.                 vma_prio_tree_insert(vma, root);
  104.                 flush_dcache_mmap_unlock(mapping);
  105.         }

  106.         if (remove_next) {
  107.                 /*
  108.                  * vma_merge has merged next into vma, and needs
  109.                  * us to remove next before dropping the locks.
  110.                  */
  111.                 /*从红黑树和链表中删除*/
  112.                 __vma_unlink(mm, next, vma);
  113.                 if (file)
  114.                         __remove_shared_vm_struct(next, file, mapping);
  115.                 if (next->anon_vma)
  116.                         __anon_vma_merge(vma, next);
  117.         } else if (insert) {
  118.                 /*
  119.                  * split_vma has split insert from vma, and needs
  120.                  * us to insert it before dropping the locks
  121.                  * (it may either follow vma or precede it).
  122.                  */
  123.                 __insert_vm_struct(mm, insert);
  124.         }

  125.         if (anon_vma)
  126.                 spin_unlock(&anon_vma->lock);
  127.         if (mapping)
  128.                 spin_unlock(&mapping->i_mmap_lock);

  129.         if (remove_next) {
  130.                 if (file)
  131.                         fput(file);
  132.                 mm->map_count--;
  133.                 mpol_free(vma_policy(next));
  134.                 kmem_cache_free(vm_area_cachep, next);
  135.                 /*
  136.                  * In mprotect's case 6 (see comments on vma_merge),
  137.                  * we must remove another next too. It would clutter
  138.                  * up the code too much to do both in one go.
  139.                  */
  140.                 if (remove_next == 2) {
  141.                         next = vma->vm_next;
  142.                         goto again;
  143.                 }
  144.         }

  145.         validate_mm(mm);
  146. }

复制代码

论坛徽章:
0
2 [报告]
发表于 2016-05-20 18:05 |只看该作者
本帖最后由 rdlkbr 于 2016-05-20 21:09 编辑

。。。。。。。。。。。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP