pagewalk.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #include <linux/mm.h>
  2. #include <linux/highmem.h>
  3. #include <linux/sched.h>
  4. #include <linux/hugetlb.h>
  5. static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
  6. struct mm_walk *walk)
  7. {
  8. pte_t *pte;
  9. int err = 0;
  10. pte = pte_offset_map(pmd, addr);
  11. for (;;) {
  12. err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, walk);
  13. if (err)
  14. break;
  15. addr += PAGE_SIZE;
  16. if (addr == end)
  17. break;
  18. pte++;
  19. }
  20. pte_unmap(pte);
  21. return err;
  22. }
  23. static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
  24. struct mm_walk *walk)
  25. {
  26. pmd_t *pmd;
  27. unsigned long next;
  28. int err = 0;
  29. pmd = pmd_offset(pud, addr);
  30. do {
  31. next = pmd_addr_end(addr, end);
  32. if (pmd_none_or_clear_bad(pmd)) {
  33. if (walk->pte_hole)
  34. err = walk->pte_hole(addr, next, walk);
  35. if (err)
  36. break;
  37. continue;
  38. }
  39. if (walk->pmd_entry)
  40. err = walk->pmd_entry(pmd, addr, next, walk);
  41. if (!err && walk->pte_entry)
  42. err = walk_pte_range(pmd, addr, next, walk);
  43. if (err)
  44. break;
  45. } while (pmd++, addr = next, addr != end);
  46. return err;
  47. }
  48. static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
  49. struct mm_walk *walk)
  50. {
  51. pud_t *pud;
  52. unsigned long next;
  53. int err = 0;
  54. pud = pud_offset(pgd, addr);
  55. do {
  56. next = pud_addr_end(addr, end);
  57. if (pud_none_or_clear_bad(pud)) {
  58. if (walk->pte_hole)
  59. err = walk->pte_hole(addr, next, walk);
  60. if (err)
  61. break;
  62. continue;
  63. }
  64. if (walk->pud_entry)
  65. err = walk->pud_entry(pud, addr, next, walk);
  66. if (!err && (walk->pmd_entry || walk->pte_entry))
  67. err = walk_pmd_range(pud, addr, next, walk);
  68. if (err)
  69. break;
  70. } while (pud++, addr = next, addr != end);
  71. return err;
  72. }
  73. /**
  74. * walk_page_range - walk a memory map's page tables with a callback
  75. * @mm: memory map to walk
  76. * @addr: starting address
  77. * @end: ending address
  78. * @walk: set of callbacks to invoke for each level of the tree
  79. *
  80. * Recursively walk the page table for the memory area in a VMA,
  81. * calling supplied callbacks. Callbacks are called in-order (first
  82. * PGD, first PUD, first PMD, first PTE, second PTE... second PMD,
  83. * etc.). If lower-level callbacks are omitted, walking depth is reduced.
  84. *
  85. * Each callback receives an entry pointer and the start and end of the
  86. * associated range, and a copy of the original mm_walk for access to
  87. * the ->private or ->mm fields.
  88. *
  89. * No locks are taken, but the bottom level iterator will map PTE
  90. * directories from highmem if necessary.
  91. *
  92. * If any callback returns a non-zero value, the walk is aborted and
  93. * the return value is propagated back to the caller. Otherwise 0 is returned.
  94. */
  95. int walk_page_range(unsigned long addr, unsigned long end,
  96. struct mm_walk *walk)
  97. {
  98. pgd_t *pgd;
  99. unsigned long next;
  100. int err = 0;
  101. struct vm_area_struct *vma;
  102. if (addr >= end)
  103. return err;
  104. if (!walk->mm)
  105. return -EINVAL;
  106. pgd = pgd_offset(walk->mm, addr);
  107. do {
  108. next = pgd_addr_end(addr, end);
  109. /*
  110. * handle hugetlb vma individually because pagetable walk for
  111. * the hugetlb page is dependent on the architecture and
  112. * we can't handled it in the same manner as non-huge pages.
  113. */
  114. vma = find_vma(walk->mm, addr);
  115. #ifdef CONFIG_HUGETLB_PAGE
  116. if (vma && is_vm_hugetlb_page(vma)) {
  117. pte_t *pte;
  118. struct hstate *hs;
  119. if (vma->vm_end < next)
  120. next = vma->vm_end;
  121. hs = hstate_vma(vma);
  122. pte = huge_pte_offset(walk->mm,
  123. addr & huge_page_mask(hs));
  124. if (pte && !huge_pte_none(huge_ptep_get(pte))
  125. && walk->hugetlb_entry)
  126. err = walk->hugetlb_entry(pte, addr,
  127. next, walk);
  128. if (err)
  129. break;
  130. continue;
  131. }
  132. #endif
  133. if (pgd_none_or_clear_bad(pgd)) {
  134. if (walk->pte_hole)
  135. err = walk->pte_hole(addr, next, walk);
  136. if (err)
  137. break;
  138. pgd++;
  139. continue;
  140. }
  141. if (walk->pgd_entry)
  142. err = walk->pgd_entry(pgd, addr, next, walk);
  143. if (!err &&
  144. (walk->pud_entry || walk->pmd_entry || walk->pte_entry))
  145. err = walk_pud_range(pgd, addr, next, walk);
  146. if (err)
  147. break;
  148. pgd++;
  149. } while (addr = next, addr != end);
  150. return err;
  151. }