pagewalk.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #include <linux/mm.h>
  2. #include <linux/highmem.h>
  3. #include <linux/sched.h>
  4. static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
  5. const struct mm_walk *walk, void *private)
  6. {
  7. pte_t *pte;
  8. int err = 0;
  9. pte = pte_offset_map(pmd, addr);
  10. do {
  11. err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private);
  12. if (err)
  13. break;
  14. } while (pte++, addr += PAGE_SIZE, addr != end);
  15. pte_unmap(pte);
  16. return err;
  17. }
  18. static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
  19. const struct mm_walk *walk, void *private)
  20. {
  21. pmd_t *pmd;
  22. unsigned long next;
  23. int err = 0;
  24. pmd = pmd_offset(pud, addr);
  25. do {
  26. next = pmd_addr_end(addr, end);
  27. if (pmd_none_or_clear_bad(pmd)) {
  28. if (walk->pte_hole)
  29. err = walk->pte_hole(addr, next, private);
  30. if (err)
  31. break;
  32. continue;
  33. }
  34. if (walk->pmd_entry)
  35. err = walk->pmd_entry(pmd, addr, next, private);
  36. if (!err && walk->pte_entry)
  37. err = walk_pte_range(pmd, addr, next, walk, private);
  38. if (err)
  39. break;
  40. } while (pmd++, addr = next, addr != end);
  41. return err;
  42. }
  43. static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
  44. const struct mm_walk *walk, void *private)
  45. {
  46. pud_t *pud;
  47. unsigned long next;
  48. int err = 0;
  49. pud = pud_offset(pgd, addr);
  50. do {
  51. next = pud_addr_end(addr, end);
  52. if (pud_none_or_clear_bad(pud)) {
  53. if (walk->pte_hole)
  54. err = walk->pte_hole(addr, next, private);
  55. if (err)
  56. break;
  57. continue;
  58. }
  59. if (walk->pud_entry)
  60. err = walk->pud_entry(pud, addr, next, private);
  61. if (!err && (walk->pmd_entry || walk->pte_entry))
  62. err = walk_pmd_range(pud, addr, next, walk, private);
  63. if (err)
  64. break;
  65. } while (pud++, addr = next, addr != end);
  66. return err;
  67. }
  68. /**
  69. * walk_page_range - walk a memory map's page tables with a callback
  70. * @mm: memory map to walk
  71. * @addr: starting address
  72. * @end: ending address
  73. * @walk: set of callbacks to invoke for each level of the tree
  74. * @private: private data passed to the callback function
  75. *
  76. * Recursively walk the page table for the memory area in a VMA,
  77. * calling supplied callbacks. Callbacks are called in-order (first
  78. * PGD, first PUD, first PMD, first PTE, second PTE... second PMD,
  79. * etc.). If lower-level callbacks are omitted, walking depth is reduced.
  80. *
  81. * Each callback receives an entry pointer, the start and end of the
  82. * associated range, and a caller-supplied private data pointer.
  83. *
  84. * No locks are taken, but the bottom level iterator will map PTE
  85. * directories from highmem if necessary.
  86. *
  87. * If any callback returns a non-zero value, the walk is aborted and
  88. * the return value is propagated back to the caller. Otherwise 0 is returned.
  89. */
  90. int walk_page_range(const struct mm_struct *mm,
  91. unsigned long addr, unsigned long end,
  92. const struct mm_walk *walk, void *private)
  93. {
  94. pgd_t *pgd;
  95. unsigned long next;
  96. int err = 0;
  97. if (addr >= end)
  98. return err;
  99. pgd = pgd_offset(mm, addr);
  100. do {
  101. next = pgd_addr_end(addr, end);
  102. if (pgd_none_or_clear_bad(pgd)) {
  103. if (walk->pte_hole)
  104. err = walk->pte_hole(addr, next, private);
  105. if (err)
  106. break;
  107. continue;
  108. }
  109. if (walk->pgd_entry)
  110. err = walk->pgd_entry(pgd, addr, next, private);
  111. if (!err &&
  112. (walk->pud_entry || walk->pmd_entry || walk->pte_entry))
  113. err = walk_pud_range(pgd, addr, next, walk, private);
  114. if (err)
  115. break;
  116. } while (pgd++, addr = next, addr != end);
  117. return err;
  118. }