1a520110eSChristoph Hellwig /* SPDX-License-Identifier: GPL-2.0 */ 2a520110eSChristoph Hellwig #ifndef _LINUX_PAGEWALK_H 3a520110eSChristoph Hellwig #define _LINUX_PAGEWALK_H 4a520110eSChristoph Hellwig 5a520110eSChristoph Hellwig #include <linux/mm.h> 6a520110eSChristoph Hellwig 77b86ac33SChristoph Hellwig struct mm_walk; 87b86ac33SChristoph Hellwig 9*49b06385SSuren Baghdasaryan /* Locking requirement during a page walk. */ 10*49b06385SSuren Baghdasaryan enum page_walk_lock { 11*49b06385SSuren Baghdasaryan /* mmap_lock should be locked for read to stabilize the vma tree */ 12*49b06385SSuren Baghdasaryan PGWALK_RDLOCK = 0, 13*49b06385SSuren Baghdasaryan /* vma will be write-locked during the walk */ 14*49b06385SSuren Baghdasaryan PGWALK_WRLOCK = 1, 15*49b06385SSuren Baghdasaryan /* vma is expected to be already write-locked during the walk */ 16*49b06385SSuren Baghdasaryan PGWALK_WRLOCK_VERIFY = 2, 17*49b06385SSuren Baghdasaryan }; 18*49b06385SSuren Baghdasaryan 19a520110eSChristoph Hellwig /** 2091ab1a41SLukas Bulwahn * struct mm_walk_ops - callbacks for walk_page_range 213afc4236SSteven Price * @pgd_entry: if set, called for each non-empty PGD (top-level) entry 223afc4236SSteven Price * @p4d_entry: if set, called for each non-empty P4D entry 233afc4236SSteven Price * @pud_entry: if set, called for each non-empty PUD entry 243afc4236SSteven Price * @pmd_entry: if set, called for each non-empty PMD entry 25a520110eSChristoph Hellwig * this handler is required to be able to handle 26a520110eSChristoph Hellwig * pmd_trans_huge() pmds. They may simply choose to 27a520110eSChristoph Hellwig * split_huge_page() instead of handling it explicitly. 28e2f8f44bSRolf Eike Beer * @pte_entry: if set, called for each PTE (lowest-level) entry, 29e2f8f44bSRolf Eike Beer * including empty ones 30b7a16c7aSSteven Price * @pte_hole: if set, called for each hole at all levels, 31e2f8f44bSRolf Eike Beer * depth is -1 if not known, 0:PGD, 1:P4D, 2:PUD, 3:PMD. 32e2f8f44bSRolf Eike Beer * Any folded depths (where PTRS_PER_P?D is equal to 1) 33e2f8f44bSRolf Eike Beer * are skipped. 34dd361e50SPeter Xu * @hugetlb_entry: if set, called for each hugetlb entry. This hook 35dd361e50SPeter Xu * function is called with the vma lock held, in order to 36dd361e50SPeter Xu * protect against a concurrent freeing of the pte_t* or 37dd361e50SPeter Xu * the ptl. In some cases, the hook function needs to drop 38dd361e50SPeter Xu * and retake the vma lock in order to avoid deadlocks 39dd361e50SPeter Xu * while calling other functions. In such cases the hook 40dd361e50SPeter Xu * function must either refrain from accessing the pte or 41dd361e50SPeter Xu * ptl after dropping the vma lock, or else revalidate 42dd361e50SPeter Xu * those items after re-acquiring the vma lock and before 43dd361e50SPeter Xu * accessing them. 44a520110eSChristoph Hellwig * @test_walk: caller specific callback function to determine whether 457b86ac33SChristoph Hellwig * we walk over the current vma or not. Returning 0 means 467b86ac33SChristoph Hellwig * "do page table walk over the current vma", returning 477b86ac33SChristoph Hellwig * a negative value means "abort current page table walk 487b86ac33SChristoph Hellwig * right now" and returning 1 means "skip the current vma" 49c31783eeSDavid Hildenbrand * Note that this callback is not called when the caller 50c31783eeSDavid Hildenbrand * passes in a single VMA as for walk_page_vma(). 51ecaad8acSThomas Hellstrom * @pre_vma: if set, called before starting walk on a non-null vma. 52ecaad8acSThomas Hellstrom * @post_vma: if set, called after a walk on a non-null vma, provided 53ecaad8acSThomas Hellstrom * that @pre_vma and the vma walk succeeded. 543afc4236SSteven Price * 553afc4236SSteven Price * p?d_entry callbacks are called even if those levels are folded on a 563afc4236SSteven Price * particular architecture/configuration. 57a520110eSChristoph Hellwig */ 587b86ac33SChristoph Hellwig struct mm_walk_ops { 593afc4236SSteven Price int (*pgd_entry)(pgd_t *pgd, unsigned long addr, 603afc4236SSteven Price unsigned long next, struct mm_walk *walk); 613afc4236SSteven Price int (*p4d_entry)(p4d_t *p4d, unsigned long addr, 623afc4236SSteven Price unsigned long next, struct mm_walk *walk); 63a520110eSChristoph Hellwig int (*pud_entry)(pud_t *pud, unsigned long addr, 64a520110eSChristoph Hellwig unsigned long next, struct mm_walk *walk); 65a520110eSChristoph Hellwig int (*pmd_entry)(pmd_t *pmd, unsigned long addr, 66a520110eSChristoph Hellwig unsigned long next, struct mm_walk *walk); 67a520110eSChristoph Hellwig int (*pte_entry)(pte_t *pte, unsigned long addr, 68a520110eSChristoph Hellwig unsigned long next, struct mm_walk *walk); 69a520110eSChristoph Hellwig int (*pte_hole)(unsigned long addr, unsigned long next, 70b7a16c7aSSteven Price int depth, struct mm_walk *walk); 71a520110eSChristoph Hellwig int (*hugetlb_entry)(pte_t *pte, unsigned long hmask, 72a520110eSChristoph Hellwig unsigned long addr, unsigned long next, 73a520110eSChristoph Hellwig struct mm_walk *walk); 74a520110eSChristoph Hellwig int (*test_walk)(unsigned long addr, unsigned long next, 75a520110eSChristoph Hellwig struct mm_walk *walk); 76ecaad8acSThomas Hellstrom int (*pre_vma)(unsigned long start, unsigned long end, 77ecaad8acSThomas Hellstrom struct mm_walk *walk); 78ecaad8acSThomas Hellstrom void (*post_vma)(struct mm_walk *walk); 79*49b06385SSuren Baghdasaryan enum page_walk_lock walk_lock; 807b86ac33SChristoph Hellwig }; 817b86ac33SChristoph Hellwig 823afc4236SSteven Price /* 833afc4236SSteven Price * Action for pud_entry / pmd_entry callbacks. 843afc4236SSteven Price * ACTION_SUBTREE is the default 853afc4236SSteven Price */ 863afc4236SSteven Price enum page_walk_action { 873afc4236SSteven Price /* Descend to next level, splitting huge pages if needed and possible */ 883afc4236SSteven Price ACTION_SUBTREE = 0, 893afc4236SSteven Price /* Continue to next entry at this level (ignoring any subtree) */ 903afc4236SSteven Price ACTION_CONTINUE = 1, 913afc4236SSteven Price /* Call again for this entry */ 923afc4236SSteven Price ACTION_AGAIN = 2 933afc4236SSteven Price }; 943afc4236SSteven Price 957b86ac33SChristoph Hellwig /** 9691ab1a41SLukas Bulwahn * struct mm_walk - walk_page_range data 977b86ac33SChristoph Hellwig * @ops: operation to call during the walk 987b86ac33SChristoph Hellwig * @mm: mm_struct representing the target process of page table walk 99e47690d7SSteven Price * @pgd: pointer to PGD; only valid with no_vma (otherwise set to NULL) 1007b86ac33SChristoph Hellwig * @vma: vma currently walked (NULL if walking outside vmas) 1013afc4236SSteven Price * @action: next action to perform (see enum page_walk_action) 102488ae6a2SSteven Price * @no_vma: walk ignoring vmas (vma will always be NULL) 1037b86ac33SChristoph Hellwig * @private: private data for callbacks' usage 1047b86ac33SChristoph Hellwig * 1057b86ac33SChristoph Hellwig * (see the comment on walk_page_range() for more details) 1067b86ac33SChristoph Hellwig */ 1077b86ac33SChristoph Hellwig struct mm_walk { 1087b86ac33SChristoph Hellwig const struct mm_walk_ops *ops; 109a520110eSChristoph Hellwig struct mm_struct *mm; 110e47690d7SSteven Price pgd_t *pgd; 111a520110eSChristoph Hellwig struct vm_area_struct *vma; 1123afc4236SSteven Price enum page_walk_action action; 113488ae6a2SSteven Price bool no_vma; 114a520110eSChristoph Hellwig void *private; 115a520110eSChristoph Hellwig }; 116a520110eSChristoph Hellwig 1177b86ac33SChristoph Hellwig int walk_page_range(struct mm_struct *mm, unsigned long start, 1187b86ac33SChristoph Hellwig unsigned long end, const struct mm_walk_ops *ops, 1197b86ac33SChristoph Hellwig void *private); 120488ae6a2SSteven Price int walk_page_range_novma(struct mm_struct *mm, unsigned long start, 121488ae6a2SSteven Price unsigned long end, const struct mm_walk_ops *ops, 122e47690d7SSteven Price pgd_t *pgd, 123488ae6a2SSteven Price void *private); 124e07cda5fSDavid Hildenbrand int walk_page_range_vma(struct vm_area_struct *vma, unsigned long start, 125e07cda5fSDavid Hildenbrand unsigned long end, const struct mm_walk_ops *ops, 126e07cda5fSDavid Hildenbrand void *private); 1277b86ac33SChristoph Hellwig int walk_page_vma(struct vm_area_struct *vma, const struct mm_walk_ops *ops, 1287b86ac33SChristoph Hellwig void *private); 129ecaad8acSThomas Hellstrom int walk_page_mapping(struct address_space *mapping, pgoff_t first_index, 130ecaad8acSThomas Hellstrom pgoff_t nr, const struct mm_walk_ops *ops, 131ecaad8acSThomas Hellstrom void *private); 132a520110eSChristoph Hellwig 133a520110eSChristoph Hellwig #endif /* _LINUX_PAGEWALK_H */ 134