xref: /openbmc/linux/include/linux/pagewalk.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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