Skip to content

Commit b7a16c7

Browse files
Steven Pricetorvalds
authored andcommitted
mm: pagewalk: add 'depth' parameter to pte_hole
The pte_hole() callback is called at multiple levels of the page tables. Code dumping the kernel page tables needs to know what at what depth the missing entry is. Add this is an extra parameter to pte_hole(). When the depth isn't know (e.g. processing a vma) then -1 is passed. The depth that is reported is the actual level where the entry is missing (ignoring any folding that is in place), i.e. any levels where PTRS_PER_P?D is set to 1 are ignored. Note that depth starts at 0 for a PGD so that PUD/PMD/PTE retain their natural numbers as levels 2/3/4. Link: http://lkml.kernel.org/r/20191218162402.45610-16-steven.price@arm.com Signed-off-by: Steven Price <steven.price@arm.com> Tested-by: Zong Li <zong.li@sifive.com> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Alexandre Ghiti <alex@ghiti.fr> Cc: Andy Lutomirski <luto@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: David S. Miller <davem@davemloft.net> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Hogan <jhogan@kernel.org> Cc: James Morse <james.morse@arm.com> Cc: Jerome Glisse <jglisse@redhat.com> Cc: "Liang, Kan" <kan.liang@linux.intel.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Burton <paul.burton@mips.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vasily Gorbik <gor@linux.ibm.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Will Deacon <will@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent c02a987 commit b7a16c7

File tree

6 files changed

+40
-16
lines changed

6 files changed

+40
-16
lines changed

fs/proc/task_mmu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
505505

506506
#ifdef CONFIG_SHMEM
507507
static int smaps_pte_hole(unsigned long addr, unsigned long end,
508-
struct mm_walk *walk)
508+
__always_unused int depth, struct mm_walk *walk)
509509
{
510510
struct mem_size_stats *mss = walk->private;
511511

@@ -1282,7 +1282,7 @@ static int add_to_pagemap(unsigned long addr, pagemap_entry_t *pme,
12821282
}
12831283

12841284
static int pagemap_pte_hole(unsigned long start, unsigned long end,
1285-
struct mm_walk *walk)
1285+
__always_unused int depth, struct mm_walk *walk)
12861286
{
12871287
struct pagemapread *pm = walk->private;
12881288
unsigned long addr = start;

include/linux/pagewalk.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ struct mm_walk;
1717
* split_huge_page() instead of handling it explicitly.
1818
* @pte_entry: if set, called for each non-empty PTE (lowest-level)
1919
* entry
20-
* @pte_hole: if set, called for each hole at all levels
20+
* @pte_hole: if set, called for each hole at all levels,
21+
* depth is -1 if not known, 0:PGD, 1:P4D, 2:PUD, 3:PMD
22+
* 4:PTE. Any folded depths (where PTRS_PER_P?D is equal
23+
* to 1) are skipped.
2124
* @hugetlb_entry: if set, called for each hugetlb entry
2225
* @test_walk: caller specific callback function to determine whether
2326
* we walk over the current vma or not. Returning 0 means
@@ -43,7 +46,7 @@ struct mm_walk_ops {
4346
int (*pte_entry)(pte_t *pte, unsigned long addr,
4447
unsigned long next, struct mm_walk *walk);
4548
int (*pte_hole)(unsigned long addr, unsigned long next,
46-
struct mm_walk *walk);
49+
int depth, struct mm_walk *walk);
4750
int (*hugetlb_entry)(pte_t *pte, unsigned long hmask,
4851
unsigned long addr, unsigned long next,
4952
struct mm_walk *walk);

mm/hmm.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ static void hmm_range_need_fault(const struct hmm_vma_walk *hmm_vma_walk,
186186
}
187187

188188
static int hmm_vma_walk_hole(unsigned long addr, unsigned long end,
189-
struct mm_walk *walk)
189+
__always_unused int depth, struct mm_walk *walk)
190190
{
191191
struct hmm_vma_walk *hmm_vma_walk = walk->private;
192192
struct hmm_range *range = hmm_vma_walk->range;
@@ -380,7 +380,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
380380
again:
381381
pmd = READ_ONCE(*pmdp);
382382
if (pmd_none(pmd))
383-
return hmm_vma_walk_hole(start, end, walk);
383+
return hmm_vma_walk_hole(start, end, -1, walk);
384384

385385
if (thp_migration_supported() && is_pmd_migration_entry(pmd)) {
386386
bool fault, write_fault;
@@ -487,7 +487,7 @@ static int hmm_vma_walk_pud(pud_t *pudp, unsigned long start, unsigned long end,
487487

488488
pud = READ_ONCE(*pudp);
489489
if (pud_none(pud)) {
490-
ret = hmm_vma_walk_hole(start, end, walk);
490+
ret = hmm_vma_walk_hole(start, end, -1, walk);
491491
goto out_unlock;
492492
}
493493

@@ -497,7 +497,7 @@ static int hmm_vma_walk_pud(pud_t *pudp, unsigned long start, unsigned long end,
497497
bool fault, write_fault;
498498

499499
if (!pud_present(pud)) {
500-
ret = hmm_vma_walk_hole(start, end, walk);
500+
ret = hmm_vma_walk_hole(start, end, -1, walk);
501501
goto out_unlock;
502502
}
503503

mm/migrate.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
21512151
#ifdef CONFIG_DEVICE_PRIVATE
21522152
static int migrate_vma_collect_hole(unsigned long start,
21532153
unsigned long end,
2154+
__always_unused int depth,
21542155
struct mm_walk *walk)
21552156
{
21562157
struct migrate_vma *migrate = walk->private;
@@ -2195,7 +2196,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
21952196

21962197
again:
21972198
if (pmd_none(*pmdp))
2198-
return migrate_vma_collect_hole(start, end, walk);
2199+
return migrate_vma_collect_hole(start, end, -1, walk);
21992200

22002201
if (pmd_trans_huge(*pmdp)) {
22012202
struct page *page;
@@ -2228,7 +2229,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
22282229
return migrate_vma_collect_skip(start, end,
22292230
walk);
22302231
if (pmd_none(*pmdp))
2231-
return migrate_vma_collect_hole(start, end,
2232+
return migrate_vma_collect_hole(start, end, -1,
22322233
walk);
22332234
}
22342235
}

mm/mincore.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ static int __mincore_unmapped_range(unsigned long addr, unsigned long end,
112112
}
113113

114114
static int mincore_unmapped_range(unsigned long addr, unsigned long end,
115+
__always_unused int depth,
115116
struct mm_walk *walk)
116117
{
117118
walk->private += __mincore_unmapped_range(addr, end,

mm/pagewalk.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@
44
#include <linux/sched.h>
55
#include <linux/hugetlb.h>
66

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+
723
static int walk_pte_range_inner(pte_t *pte, unsigned long addr,
824
unsigned long end, struct mm_walk *walk)
925
{
@@ -49,14 +65,15 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
4965
unsigned long next;
5066
const struct mm_walk_ops *ops = walk->ops;
5167
int err = 0;
68+
int depth = real_depth(3);
5269

5370
pmd = pmd_offset(pud, addr);
5471
do {
5572
again:
5673
next = pmd_addr_end(addr, end);
5774
if (pmd_none(*pmd) || (!walk->vma && !walk->no_vma)) {
5875
if (ops->pte_hole)
59-
err = ops->pte_hole(addr, next, walk);
76+
err = ops->pte_hole(addr, next, depth, walk);
6077
if (err)
6178
break;
6279
continue;
@@ -106,14 +123,15 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
106123
unsigned long next;
107124
const struct mm_walk_ops *ops = walk->ops;
108125
int err = 0;
126+
int depth = real_depth(2);
109127

110128
pud = pud_offset(p4d, addr);
111129
do {
112130
again:
113131
next = pud_addr_end(addr, end);
114132
if (pud_none(*pud) || (!walk->vma && !walk->no_vma)) {
115133
if (ops->pte_hole)
116-
err = ops->pte_hole(addr, next, walk);
134+
err = ops->pte_hole(addr, next, depth, walk);
117135
if (err)
118136
break;
119137
continue;
@@ -154,13 +172,14 @@ static int walk_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end,
154172
unsigned long next;
155173
const struct mm_walk_ops *ops = walk->ops;
156174
int err = 0;
175+
int depth = real_depth(1);
157176

158177
p4d = p4d_offset(pgd, addr);
159178
do {
160179
next = p4d_addr_end(addr, end);
161180
if (p4d_none_or_clear_bad(p4d)) {
162181
if (ops->pte_hole)
163-
err = ops->pte_hole(addr, next, walk);
182+
err = ops->pte_hole(addr, next, depth, walk);
164183
if (err)
165184
break;
166185
continue;
@@ -192,7 +211,7 @@ static int walk_pgd_range(unsigned long addr, unsigned long end,
192211
next = pgd_addr_end(addr, end);
193212
if (pgd_none_or_clear_bad(pgd)) {
194213
if (ops->pte_hole)
195-
err = ops->pte_hole(addr, next, walk);
214+
err = ops->pte_hole(addr, next, 0, walk);
196215
if (err)
197216
break;
198217
continue;
@@ -239,7 +258,7 @@ static int walk_hugetlb_range(unsigned long addr, unsigned long end,
239258
if (pte)
240259
err = ops->hugetlb_entry(pte, hmask, addr, next, walk);
241260
else if (ops->pte_hole)
242-
err = ops->pte_hole(addr, next, walk);
261+
err = ops->pte_hole(addr, next, -1, walk);
243262

244263
if (err)
245264
break;
@@ -283,7 +302,7 @@ static int walk_page_test(unsigned long start, unsigned long end,
283302
if (vma->vm_flags & VM_PFNMAP) {
284303
int err = 1;
285304
if (ops->pte_hole)
286-
err = ops->pte_hole(start, end, walk);
305+
err = ops->pte_hole(start, end, -1, walk);
287306
return err ? err : 1;
288307
}
289308
return 0;

0 commit comments

Comments
 (0)