Skip to content

Commit 416716e

Browse files
committed
Merge tag 'powerpc-4.1-4' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux
Pull powerpc fixes from Michael Ellerman: - THP/hugetlb fixes from Aneesh. - MCE fix from Daniel. - TOC fix from Anton. * tag 'powerpc-4.1-4' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux: powerpc: Align TOC to 256 bytes powerpc/mce: fix off by one errors in mce event handling powerpc/mm: Return NULL for not present hugetlb page powerpc/thp: Serialize pmd clear against a linux page table walk.
2 parents 68465bb + 5e95235 commit 416716e

File tree

4 files changed

+30
-11
lines changed

4 files changed

+30
-11
lines changed

arch/powerpc/kernel/mce.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
7373
uint64_t nip, uint64_t addr)
7474
{
7575
uint64_t srr1;
76-
int index = __this_cpu_inc_return(mce_nest_count);
76+
int index = __this_cpu_inc_return(mce_nest_count) - 1;
7777
struct machine_check_event *mce = this_cpu_ptr(&mce_event[index]);
7878

7979
/*
@@ -184,7 +184,7 @@ void machine_check_queue_event(void)
184184
if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
185185
return;
186186

187-
index = __this_cpu_inc_return(mce_queue_count);
187+
index = __this_cpu_inc_return(mce_queue_count) - 1;
188188
/* If queue is full, just return for now. */
189189
if (index >= MAX_MC_EVT) {
190190
__this_cpu_dec(mce_queue_count);

arch/powerpc/kernel/vmlinux.lds.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ SECTIONS
213213
*(.opd)
214214
}
215215

216+
. = ALIGN(256);
216217
.got : AT(ADDR(.got) - LOAD_OFFSET) {
217218
__toc_start = .;
218219
#ifndef CONFIG_RELOCATABLE

arch/powerpc/mm/hugetlbpage.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -689,27 +689,34 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
689689
struct page *
690690
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
691691
{
692-
pte_t *ptep;
693-
struct page *page;
692+
pte_t *ptep, pte;
694693
unsigned shift;
695694
unsigned long mask, flags;
695+
struct page *page = ERR_PTR(-EINVAL);
696+
697+
local_irq_save(flags);
698+
ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
699+
if (!ptep)
700+
goto no_page;
701+
pte = READ_ONCE(*ptep);
696702
/*
703+
* Verify it is a huge page else bail.
697704
* Transparent hugepages are handled by generic code. We can skip them
698705
* here.
699706
*/
700-
local_irq_save(flags);
701-
ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
707+
if (!shift || pmd_trans_huge(__pmd(pte_val(pte))))
708+
goto no_page;
702709

703-
/* Verify it is a huge page else bail. */
704-
if (!ptep || !shift || pmd_trans_huge(*(pmd_t *)ptep)) {
705-
local_irq_restore(flags);
706-
return ERR_PTR(-EINVAL);
710+
if (!pte_present(pte)) {
711+
page = NULL;
712+
goto no_page;
707713
}
708714
mask = (1UL << shift) - 1;
709-
page = pte_page(*ptep);
715+
page = pte_page(pte);
710716
if (page)
711717
page += (address & mask) / PAGE_SIZE;
712718

719+
no_page:
713720
local_irq_restore(flags);
714721
return page;
715722
}

arch/powerpc/mm/pgtable_64.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,17 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm,
839839
* hash fault look at them.
840840
*/
841841
memset(pgtable, 0, PTE_FRAG_SIZE);
842+
/*
843+
* Serialize against find_linux_pte_or_hugepte which does lock-less
844+
* lookup in page tables with local interrupts disabled. For huge pages
845+
* it casts pmd_t to pte_t. Since format of pte_t is different from
846+
* pmd_t we want to prevent transit from pmd pointing to page table
847+
* to pmd pointing to huge page (and back) while interrupts are disabled.
848+
* We clear pmd to possibly replace it with page table pointer in
849+
* different code paths. So make sure we wait for the parallel
850+
* find_linux_pte_or_hugepage to finish.
851+
*/
852+
kick_all_cpus_sync();
842853
return old_pmd;
843854
}
844855

0 commit comments

Comments
 (0)