Chinaunix首页 | 论坛 | 博客
  • 博客访问: 913365
  • 博文数量: 119
  • 博客积分: 2493
  • 博客等级: 大尉
  • 技术积分: 2363
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-03 14:00
文章分类

全部博文(119)

文章存档

2013年(19)

2012年(100)

分类: LINUX

2012-08-10 18:18:04

       内核时常需要对进程的某个虚存区进行操作,那就需要找到该虚存区,内核里面
就提供了一个内核API,可以由一个虚拟地址,找到该地址所在的虚存区。
-------------------------------------------------------------------------------
1,该内核API解析。
  1. 1590 /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
  2. 1591 struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
  3. 1592 {
  4. 1593 struct vm_area_struct *vma = NULL;
  5. 1594
  6. 1595 if (mm) {
  7. 1596 /* Check the cache first. */
  8. 1597 /* (Cache hit rate is typically around 35%.) */
  9. 1598 vma = mm->mmap_cache;//先把缓存中的一个vma拿出来,看是否符合要求。
  10.      //如果符合要求则把缓存中的地址返回后退出,不符合要求则到红黑树中去找
  11. 1599 if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
  12. 1600 struct rb_node * rb_node;
  13. 1601
  14. 1602 rb_node = mm->mm_rb.rb_node;//获取红黑树的根。
  15. 1603 vma = NULL;
  16. 1604
  17. 1605 while (rb_node) {
  18. 1606 struct vm_area_struct * vma_tmp;
  19. 1607
  20. 1608 vma_tmp = rb_entry(rb_node,//由红黑树节点返回到该节点的 struct vm_area_struct *

  21. 1609 struct vm_area_struct, vm_rb);
  22. 1610
  23. 1611 if (vma_tmp->vm_end > addr) { //如果addr小于vm_end
  24. 1612 vma = vma_tmp;
  25. 1613 if (vma_tmp->vm_start <= addr)
  26. 1614 break;
  27. 1615 rb_node = rb_node->rb_left;//朝左走
  28. 1616 } else
  29. 1617 rb_node = rb_node->rb_right;//朝右走
  30. 1618 }
  31. 1619 if (vma)
  32. 1620 mm->mmap_cache = vma;//将找到的vma写入到缓存中
  33. 1621 }
  34. 1622 }
  35. 1623 return vma;//返回vma指针
  36. 1624 }
该函数还是很好理解的,mm_struct中有一个字段mmap_cache,用来缓存上一次使用的vma
的指针,在这次查找vma时,先在该缓存中取出这个vma,看这个vma是不是要查找的vma,
如果是就将这个vma的指针返回,不是然后再到红黑树中去找。
--------------------------------------------------------------------------------------
2,该函数的返回。

该函数的返回和一般想象的不太一样,分如上三种情况。
case 1,如果addr 位于某个虚存区上,则返回该虚存区的指针。
case 2,如果addr 没有位于那个虚存区,而是在空洞上,则返回该空洞的上一个虚存区的指针。
           例如图上的case 2,查询addr返回的就是vma2
case 3,如果addr 位于空洞上,而且没有上一个虚存区,则返回NULL。
----------------------------------------------------------------------------------------------
4,实战。(代码验证理论)
  1. static int __init find_vma_init(void)
  2. {
  3.     struct mm_struct *mm;
  4.     struct vm_area_struct *vma;
  5.     unsigned long addr;
  6.     unsigned long addr2 = (unsigned long)0xffff0000;

  7.     mm = current->mm;
  8.     addr =     mm->mmap->vm_start + 1;
  9.     printk("<0>addr = 0x%lx\n",addr);
  10.     vma = find_vma(mm,addr);
  11.     if (vma != NULL) {
  12.         printk("<0>vma->vm_start = 0x%lx\n",vma->vm_start);
  13.         printk("<0>vma->vm_end = 0x%lx\n",vma->vm_end);
  14.      printk("<0>page_number = %lu\n",vma_pages(vma));
  15.     } else {
  16.         printk("<0>don't find the vma!\n");
  17.     }
  18.     printk("<0>-----------------------------------\n");
  19.     addr = mm->mmap->vm_start - 1;
  20.     printk("<0>addr = 0x%lx\n",addr);
  21.     vma = find_vma(mm,addr);
  22.     if (vma != NULL) {
  23.         printk("<0>vma->vm_start = 0x%lx\n",vma->vm_start);
  24.         printk("<0>vma->vm_end = 0x%lx\n",vma->vm_end);
  25.      printk("<0>page_number = %lu\n",vma_pages(vma));
  26.     } else {
  27.         printk("<0>don't find the vma!\n");
  28.     }
  29.     printk("<0>-----------------------------------\n");
  30.     addr = addr2;
  31.     printk("<0>addr = 0x%lx\n",addr);
  32.     vma = find_vma(mm,addr);
  33.     if (vma != NULL) {
  34.         printk("<0>vma->vm_start = 0x%lx\n",vma->vm_start);
  35.         printk("<0>vma->vm_end = 0x%lx\n",vma->vm_end);
  36.      printk("<0>page_number = %lu\n",vma_pages(vma));
  37.     } else {
  38.         printk("<0>don't find the vma!\n");
  39.     }
  40.     printk("<0>-----------------------------------\n");
  41.     return 0;    
  42. }
内核API:vma_pages()用来求得找到的虚存区有多少个虚拟页,实现也很简单。
虚存区的尾地址-首地址,然后除以4KB,即虚存区的页的个数。
实现代码:
  1. 1367 static inline unsigned long vma_pages(struct vm_area_struct *vma)
  2. 1368 {
  3. 1369 return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
  4. 1370 }
---------------------------------------------------------------------------
4,模块完整代码。
 find_vma.rar  
----------------------------------------------------------------------------

参考:http://edsionte.com/techblog/archives/3403
阅读(1371) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~