|
4 | 4 | #include <linux/sched.h> |
5 | 5 | #include <linux/hugetlb.h> |
6 | 6 |
|
| 7 | +/* |
| 8 | + * We want to know the real level where a entry is located ignoring any |
| 9 | + * folding of levels which may be happening. For example if p4d is folded then |
| 10 | + * a missing entry found at level 1 (p4d) is actually at level 0 (pgd). |
| 11 | + */ |
| 12 | +static int real_depth(int depth) |
| 13 | +{ |
| 14 | + if (depth == 3 && PTRS_PER_PMD == 1) |
| 15 | + depth = 2; |
| 16 | + if (depth == 2 && PTRS_PER_PUD == 1) |
| 17 | + depth = 1; |
| 18 | + if (depth == 1 && PTRS_PER_P4D == 1) |
| 19 | + depth = 0; |
| 20 | + return depth; |
| 21 | +} |
| 22 | + |
7 | 23 | static int walk_pte_range_inner(pte_t *pte, unsigned long addr, |
8 | 24 | unsigned long end, struct mm_walk *walk) |
9 | 25 | { |
@@ -49,14 +65,15 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, |
49 | 65 | unsigned long next; |
50 | 66 | const struct mm_walk_ops *ops = walk->ops; |
51 | 67 | int err = 0; |
| 68 | + int depth = real_depth(3); |
52 | 69 |
|
53 | 70 | pmd = pmd_offset(pud, addr); |
54 | 71 | do { |
55 | 72 | again: |
56 | 73 | next = pmd_addr_end(addr, end); |
57 | 74 | if (pmd_none(*pmd) || (!walk->vma && !walk->no_vma)) { |
58 | 75 | if (ops->pte_hole) |
59 | | - err = ops->pte_hole(addr, next, walk); |
| 76 | + err = ops->pte_hole(addr, next, depth, walk); |
60 | 77 | if (err) |
61 | 78 | break; |
62 | 79 | continue; |
@@ -106,14 +123,15 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end, |
106 | 123 | unsigned long next; |
107 | 124 | const struct mm_walk_ops *ops = walk->ops; |
108 | 125 | int err = 0; |
| 126 | + int depth = real_depth(2); |
109 | 127 |
|
110 | 128 | pud = pud_offset(p4d, addr); |
111 | 129 | do { |
112 | 130 | again: |
113 | 131 | next = pud_addr_end(addr, end); |
114 | 132 | if (pud_none(*pud) || (!walk->vma && !walk->no_vma)) { |
115 | 133 | if (ops->pte_hole) |
116 | | - err = ops->pte_hole(addr, next, walk); |
| 134 | + err = ops->pte_hole(addr, next, depth, walk); |
117 | 135 | if (err) |
118 | 136 | break; |
119 | 137 | continue; |
@@ -154,13 +172,14 @@ static int walk_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end, |
154 | 172 | unsigned long next; |
155 | 173 | const struct mm_walk_ops *ops = walk->ops; |
156 | 174 | int err = 0; |
| 175 | + int depth = real_depth(1); |
157 | 176 |
|
158 | 177 | p4d = p4d_offset(pgd, addr); |
159 | 178 | do { |
160 | 179 | next = p4d_addr_end(addr, end); |
161 | 180 | if (p4d_none_or_clear_bad(p4d)) { |
162 | 181 | if (ops->pte_hole) |
163 | | - err = ops->pte_hole(addr, next, walk); |
| 182 | + err = ops->pte_hole(addr, next, depth, walk); |
164 | 183 | if (err) |
165 | 184 | break; |
166 | 185 | continue; |
@@ -192,7 +211,7 @@ static int walk_pgd_range(unsigned long addr, unsigned long end, |
192 | 211 | next = pgd_addr_end(addr, end); |
193 | 212 | if (pgd_none_or_clear_bad(pgd)) { |
194 | 213 | if (ops->pte_hole) |
195 | | - err = ops->pte_hole(addr, next, walk); |
| 214 | + err = ops->pte_hole(addr, next, 0, walk); |
196 | 215 | if (err) |
197 | 216 | break; |
198 | 217 | continue; |
@@ -239,7 +258,7 @@ static int walk_hugetlb_range(unsigned long addr, unsigned long end, |
239 | 258 | if (pte) |
240 | 259 | err = ops->hugetlb_entry(pte, hmask, addr, next, walk); |
241 | 260 | else if (ops->pte_hole) |
242 | | - err = ops->pte_hole(addr, next, walk); |
| 261 | + err = ops->pte_hole(addr, next, -1, walk); |
243 | 262 |
|
244 | 263 | if (err) |
245 | 264 | break; |
@@ -283,7 +302,7 @@ static int walk_page_test(unsigned long start, unsigned long end, |
283 | 302 | if (vma->vm_flags & VM_PFNMAP) { |
284 | 303 | int err = 1; |
285 | 304 | if (ops->pte_hole) |
286 | | - err = ops->pte_hole(start, end, walk); |
| 305 | + err = ops->pte_hole(start, end, -1, walk); |
287 | 306 | return err ? err : 1; |
288 | 307 | } |
289 | 308 | return 0; |
|
0 commit comments