1.static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
2. unsigned long start, unsigned long end)
3.{
4. unsigned long first = start & PGDIR_MASK;
5. unsigned long last = end + PGDIR_SIZE - 1;
6. unsigned long start_index, end_index;
7.
8. if (!prev) {
9. prev = mm->mmap;
10. if (!prev)
11. goto no_mmaps;
12. if (prev->vm_end > start) {
13. if (last > prev->vm_start)
14. last = prev->vm_start;
15. goto no_mmaps;
16. }
17. }
18. for (;;) {
19. struct vm_area_struct *next = prev->vm_next;
20.
21. if (next) {
22. if (next->vm_start < start) {
23. prev = next;
24. continue;
25. }
26. if (last > next->vm_start)
27. last = next->vm_start;
28. }
29. if (prev->vm_end > first)
30. first = prev->vm_end + PGDIR_SIZE - 1;
31. break;
32. }
33.no_mmaps:
34. /*
35. * If the PGD bits are not consecutive in the virtual address, the
36. * old method of shifting the VA >> by PGDIR_SHIFT doesn't work.
37. */
38. start_index = pgd_index(first);
39. end_index = pgd_index(last);
40. if (end_index > start_index) {
41. clear_page_tables(mm, start_index, end_index - start_index);
42. flush_tlb_pgtables(mm, first & PGDIR_MASK, last & PGDIR_MASK);
43. }
sys_brk系统调用中,在调用这个函数之前,start到end这块地址对应的vm_area结构体已经被释放了,对应的物理页面的映射也已经断开,在mm->mmap链表中,是找不到start到end对应的vm区间的。free_pgtables作用就是释放所有页表项都已经清零的页表所占的内存,在22行先找到起始地址大于等于start的vm区间,然后判断last是不是大于这个区间的起始地址 ,如果是,说明first到last之间不全是空洞,就需要把这个区间的起始地址赋值给last。同样,还要判断first是不是大于前一个区间的结束地址,是的话,就没问题,否则first地址开始的这一页页面表项就还不是完全清零的,first就需要移动到prev->vm_end后面的一个页目录项对应的页表
prev->vm_start prev->vm_end first start last next->vm_start