| From foo@baz Wed Aug 22 09:42:09 CEST 2018 |
| From: Greg Ungerer <gerg@linux-m68k.org> |
| Date: Mon, 18 Jun 2018 15:34:14 +1000 |
| Subject: m68k: fix "bad page state" oops on ColdFire boot |
| |
| From: Greg Ungerer <gerg@linux-m68k.org> |
| |
| [ Upstream commit ecd60532e060e45c63c57ecf1c8549b1d656d34d ] |
| |
| Booting a ColdFire m68k core with MMU enabled causes a "bad page state" |
| oops since commit 1d40a5ea01d5 ("mm: mark pages in use for page tables"): |
| |
| BUG: Bad page state in process sh pfn:01ce2 |
| page:004fefc8 count:0 mapcount:-1024 mapping:00000000 index:0x0 |
| flags: 0x0() |
| raw: 00000000 00000000 00000000 fffffbff 00000000 00000100 00000200 00000000 |
| raw: 039c4000 |
| page dumped because: nonzero mapcount |
| Modules linked in: |
| CPU: 0 PID: 22 Comm: sh Not tainted 4.17.0-07461-g1d40a5ea01d5 #13 |
| |
| Fix by calling pgtable_page_dtor() in our __pte_free_tlb() code path, |
| so that the PG_table flag is cleared before we free the pte page. |
| |
| Note that I had to change the type of pte_free() to be static from |
| extern. Otherwise you get a lot of warnings like this: |
| |
| ./arch/m68k/include/asm/mcf_pgalloc.h:80:2: warning: ‘pgtable_page_dtor’ is static but used in inline function ‘pte_free’ which is not static |
| pgtable_page_dtor(page); |
| ^ |
| |
| And making it static is consistent with our use of this in the other |
| m68k pgalloc definitions of pte_free(). |
| |
| Signed-off-by: Greg Ungerer <gerg@linux-m68k.org> |
| CC: Matthew Wilcox <willy@infradead.org> |
| Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/m68k/include/asm/mcf_pgalloc.h | 4 +++- |
| 1 file changed, 3 insertions(+), 1 deletion(-) |
| |
| --- a/arch/m68k/include/asm/mcf_pgalloc.h |
| +++ b/arch/m68k/include/asm/mcf_pgalloc.h |
| @@ -43,6 +43,7 @@ extern inline pmd_t *pmd_alloc_kernel(pg |
| static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page, |
| unsigned long address) |
| { |
| + pgtable_page_dtor(page); |
| __free_page(page); |
| } |
| |
| @@ -73,8 +74,9 @@ static inline struct page *pte_alloc_one |
| return page; |
| } |
| |
| -extern inline void pte_free(struct mm_struct *mm, struct page *page) |
| +static inline void pte_free(struct mm_struct *mm, struct page *page) |
| { |
| + pgtable_page_dtor(page); |
| __free_page(page); |
| } |
| |