summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
authorChristophe Leroy <christophe.leroy@csgroup.eu>2020-12-12 13:41:25 +0000
committerMichael Ellerman <mpe@ellerman.id.au>2020-12-15 22:22:07 +1100
commit2198d4934ee8b81341a84c9ec8bb25b4b0d02522 (patch)
tree2686064f99430e1ca942f8e9e496bc1a47b8ab87 /arch
parent87fb4978ef8f7e3d6f51ea8e259638c4e96f2fc0 (diff)
downloadlinux-2198d4934ee8b81341a84c9ec8bb25b4b0d02522.tar.gz
powerpc/mm: Fix hugetlb_free_pmd_range() and hugetlb_free_pud_range()
Commit 7bfe54b5f165 ("powerpc/mm: Refactor the floor/ceiling check in
hugetlb range freeing functions") inadvertely removed the mask
applied to start parameter in those two functions, leading to the
following crash on power9.

  LTP: starting hugemmap05_1 (hugemmap05 -m)
  ------------[ cut here ]------------
  kernel BUG at arch/powerpc/mm/book3s64/pgtable.c:387!
  Oops: Exception in kernel mode, sig: 5 [#1]
  LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=256 NUMA PowerNV
  ...
  CPU: 99 PID: 308 Comm: ksoftirqd/99 Tainted: G           O      5.10.0-rc7-next-20201211 #1
  NIP:  c00000000005dbec LR: c0000000003352f4 CTR: 0000000000000000
  REGS: c00020000bb6f830 TRAP: 0700   Tainted: G           O       (5.10.0-rc7-next-20201211)
  MSR:  900000000282b033 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR: 24002284  XER: 20040000
  GPR00: c0000000003352f4 c00020000bb6fad0 c000000007f70b00 c0002000385b3ff0
  GPR04: 0000000000000000 0000000000000003 c00020000bb6f8b4 0000000000000001
  GPR08: 0000000000000001 0000000000000009 0000000000000008 0000000000000002
  GPR12: 0000000024002488 c000201fff649c00 c000000007f2a20c 0000000000000000
  GPR16: 0000000000000007 0000000000000000 c000000000194d10 c000000000194d10
  GPR24: 0000000000000014 0000000000000015 c000201cc6e72398 c000000007fac4b4
  GPR28: c000000007f2bf80 c000000007fac2f8 0000000000000008 c000200033870000
  NIP [c00000000005dbec] __tlb_remove_table+0x1dc/0x1e0
                         pgtable_free at arch/powerpc/mm/book3s64/pgtable.c:387
                         (inlined by) __tlb_remove_table at arch/powerpc/mm/book3s64/pgtable.c:405
  LR [c0000000003352f4] tlb_remove_table_rcu+0x54/0xa0
  Call Trace:
    __tlb_remove_table+0x13c/0x1e0 (unreliable)
    tlb_remove_table_rcu+0x54/0xa0
    __tlb_remove_table_free at mm/mmu_gather.c:101
    (inlined by) tlb_remove_table_rcu at mm/mmu_gather.c:156
    rcu_core+0x35c/0xbb0
    rcu_do_batch at kernel/rcu/tree.c:2502
    (inlined by) rcu_core at kernel/rcu/tree.c:2737
    __do_softirq+0x480/0x704
    run_ksoftirqd+0x74/0xd0
    run_ksoftirqd at kernel/softirq.c:651
    (inlined by) run_ksoftirqd at kernel/softirq.c:642
    smpboot_thread_fn+0x278/0x320
    kthread+0x1c4/0x1d0
    ret_from_kernel_thread+0x5c/0x80

Properly apply the masks before calling pmd_free_tlb() and
pud_free_tlb() respectively.

Fixes: 7bfe54b5f165 ("powerpc/mm: Refactor the floor/ceiling check in hugetlb range freeing functions")
Reported-by: Qian Cai <qcai@redhat.com>
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/56feccd7b6fcd98e353361a233fa7bb8e67c3164.1607780469.git.christophe.leroy@csgroup.eu
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/mm/hugetlbpage.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f8d8a4988e15..8b3cc4d688e8 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -396,9 +396,9 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
 	if (range_is_outside_limits(start, end, floor, ceiling, PUD_MASK))
 		return;
 
-	pmd = pmd_offset(pud, start);
+	pmd = pmd_offset(pud, start & PUD_MASK);
 	pud_clear(pud);
-	pmd_free_tlb(tlb, pmd, start);
+	pmd_free_tlb(tlb, pmd, start & PUD_MASK);
 	mm_dec_nr_pmds(tlb->mm);
 }
 
@@ -439,9 +439,9 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, p4d_t *p4d,
 	if (range_is_outside_limits(start, end, floor, ceiling, PGDIR_MASK))
 		return;
 
-	pud = pud_offset(p4d, start);
+	pud = pud_offset(p4d, start & PGDIR_MASK);
 	p4d_clear(p4d);
-	pud_free_tlb(tlb, pud, start);
+	pud_free_tlb(tlb, pud, start & PGDIR_MASK);
 	mm_dec_nr_puds(tlb->mm);
 }