pagewalk.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. split_huge_page_pmd(walk->mm, pmd);
  33. if (pmd_none_or_clear_bad(pmd)) {
  34. if (walk->pte_hole)
  35. err = walk->pte_hole(addr, next, walk);
  36. if (err)
  37. break;
  38. continue;
  39. }
  40. if (walk->pmd_entry)
  41. err = walk->pmd_entry(pmd, addr, next, walk);
  42. if (!err && walk->pte_entry)
  43. err = walk_pte_range(pmd, addr, next, walk);
  44. if (err)
  45. break;
  46. } while (pmd++, addr = next, addr != end);
  47. return err;
  48. }
  49. static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
  50. struct mm_walk *walk)
  51. {
  52. pud_t *pud;
  53. unsigned long next;
  54. int err = 0;
  55. pud = pud_offset(pgd, addr);
  56. do {
  57. next = pud_addr_end(addr, end);
  58. if (pud_none_or_clear_bad(pud)) {
  59. if (walk->pte_hole)
  60. err = walk->pte_hole(addr, next, walk);
  61. if (err)
  62. break;
  63. continue;
  64. }
  65. if (walk->pud_entry)
  66. err = walk->pud_entry(pud, addr, next, walk);
  67. if (!err && (walk->pmd_entry || walk->pte_entry))
  68. err = walk_pmd_range(pud, addr, next, walk);
  69. if (err)
  70. break;
  71. } while (pud++, addr = next, addr != end);
  72. return err;
  73. }
  74. #ifdef CONFIG_HUGETLB_PAGE
  75. static unsigned long hugetlb_entry_end(struct hstate *h, unsigned long addr,
  76. unsigned long end)
  77. {
  78. unsigned long boundary = (addr & huge_page_mask(h)) + huge_page_size(h);
  79. return boundary < end ? boundary : end;
  80. }
  81. static int walk_hugetlb_range(struct vm_area_struct *vma,
  82. unsigned long addr, unsigned long end,
  83. struct mm_walk *walk)
  84. {
  85. struct hstate *h = hstate_vma(vma);
  86. unsigned long next;
  87. unsigned long hmask = huge_page_mask(h);
  88. pte_t *pte;
  89. int err = 0;
  90. do {
  91. next = hugetlb_entry_end(h, addr, end);
  92. pte = huge_pte_offset(walk->mm, addr & hmask);
  93. if (pte && walk->hugetlb_entry)
  94. err = walk->hugetlb_entry(pte, hmask, addr, next, walk);
  95. if (err)
  96. return err;
  97. } while (addr = next, addr != end);
  98. return 0;
  99. }
  100. #endif
  101. /**
  102. * walk_page_range - walk a memory map's page tables with a callback
  103. * @mm: memory map to walk
  104. * @addr: starting address
  105. * @end: ending address
  106. * @walk: set of callbacks to invoke for each level of the tree
  107. *
  108. * Recursively walk the page table for the memory area in a VMA,
  109. * calling supplied callbacks. Callbacks are called in-order (first
  110. * PGD, first PUD, first PMD, first PTE, second PTE... second PMD,
  111. * etc.). If lower-level callbacks are omitted, walking depth is reduced.
  112. *
  113. * Each callback receives an entry pointer and the start and end of the
  114. * associated range, and a copy of the original mm_walk for access to
  115. * the ->private or ->mm fields.
  116. *
  117. * No locks are taken, but the bottom level iterator will map PTE
  118. * directories from highmem if necessary.
  119. *
  120. * If any callback returns a non-zero value, the walk is aborted and
  121. * the return value is propagated back to the caller. Otherwise 0 is returned.
  122. */
  123. int walk_page_range(unsigned long addr, unsigned long end,
  124. struct mm_walk *walk)
  125. {
  126. pgd_t *pgd;
  127. unsigned long next;
  128. int err = 0;
  129. if (addr >= end)
  130. return err;
  131. if (!walk->mm)
  132. return -EINVAL;
  133. pgd = pgd_offset(walk->mm, addr);
  134. do {
  135. struct vm_area_struct *uninitialized_var(vma);
  136. next = pgd_addr_end(addr, end);
  137. #ifdef CONFIG_HUGETLB_PAGE
  138. /*
  139. * handle hugetlb vma individually because pagetable walk for
  140. * the hugetlb page is dependent on the architecture and
  141. * we can't handled it in the same manner as non-huge pages.
  142. */
  143. vma = find_vma(walk->mm, addr);
  144. if (vma && is_vm_hugetlb_page(vma)) {
  145. if (vma->vm_end < next)
  146. next = vma->vm_end;
  147. /*
  148. * Hugepage is very tightly coupled with vma, so
  149. * walk through hugetlb entries within a given vma.
  150. */
  151. err = walk_hugetlb_range(vma, addr, next, walk);
  152. if (err)
  153. break;
  154. pgd = pgd_offset(walk->mm, next);
  155. continue;
  156. }
  157. #endif
  158. if (pgd_none_or_clear_bad(pgd)) {
  159. if (walk->pte_hole)
  160. err = walk->pte_hole(addr, next, walk);
  161. if (err)
  162. break;
  163. pgd++;
  164. continue;
  165. }
  166. if (walk->pgd_entry)
  167. err = walk->pgd_entry(pgd, addr, next, walk);
  168. if (!err &&
  169. (walk->pud_entry || walk->pmd_entry || walk->pte_entry))
  170. err = walk_pud_range(pgd, addr, next, walk);
  171. if (err)
  172. break;
  173. pgd++;
  174. } while (addr = next, addr != end);
  175. return err;
  176. }