Message ID | 20201025101555.3057-5-rppt@kernel.org (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | arch, mm: improve robustness of direct map manipulation | expand |
On Sun, 2020-10-25 at 12:15 +0200, Mike Rapoport wrote: > index 7f248fc45317..16f878c26667 100644 > --- a/arch/x86/mm/pat/set_memory.c > +++ b/arch/x86/mm/pat/set_memory.c > @@ -2228,7 +2228,6 @@ void __kernel_map_pages(struct page *page, int > numpages, int enable) > } > #endif /* CONFIG_DEBUG_PAGEALLOC */ > > -#ifdef CONFIG_HIBERNATION > bool kernel_page_present(struct page *page) > { > unsigned int level; > @@ -2240,7 +2239,6 @@ bool kernel_page_present(struct page *page) > pte = lookup_address((unsigned long)page_address(page), > &level); > return (pte_val(*pte) & _PAGE_PRESENT); > } > -#endif /* CONFIG_HIBERNATION */ This is only used by hibernate today right? Makes sense that it should return a correct answer if someone starts to use it without looking too closely at the header. But could we just remove the default static inline return true implementation and let the linker fail if someone starts to use it outside hibernate? Then we could leave it compiled out until then. Also it looks like riscv does not have ARCH_HIBERNATION_POSSIBLE so the new function added here couldn't be used yet. You could also just let the linker catch it if riscv ever enables hibernate?
On Mon, Oct 26, 2020 at 12:54:01AM +0000, Edgecombe, Rick P wrote: > On Sun, 2020-10-25 at 12:15 +0200, Mike Rapoport wrote: > > index 7f248fc45317..16f878c26667 100644 > > --- a/arch/x86/mm/pat/set_memory.c > > +++ b/arch/x86/mm/pat/set_memory.c > > @@ -2228,7 +2228,6 @@ void __kernel_map_pages(struct page *page, int > > numpages, int enable) > > } > > #endif /* CONFIG_DEBUG_PAGEALLOC */ > > > > -#ifdef CONFIG_HIBERNATION > > bool kernel_page_present(struct page *page) > > { > > unsigned int level; > > @@ -2240,7 +2239,6 @@ bool kernel_page_present(struct page *page) > > pte = lookup_address((unsigned long)page_address(page), > > &level); > > return (pte_val(*pte) & _PAGE_PRESENT); > > } > > -#endif /* CONFIG_HIBERNATION */ > > This is only used by hibernate today right? Makes sense that it should > return a correct answer if someone starts to use it without looking too > closely at the header. But could we just remove the default static > inline return true implementation and let the linker fail if someone > starts to use it outside hibernate? Then we could leave it compiled out > until then. Hmm, I'm not sure I follow you here. We'd need some stub for architectures that have ARCH_HIBERNATION_POSSIBLE and do not have CONFIG_ARCH_HAS_SET_DIRECT_MAP. I don't see how the kernel would compile for ppc or sparc with hibernation enabled if I remove the default implementation. > Also it looks like riscv does not have ARCH_HIBERNATION_POSSIBLE so the > new function added here couldn't be used yet. You could also just let > the linker catch it if riscv ever enables hibernate?
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 9384fd8fc13c..45217f21f1fe 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -140,6 +140,7 @@ int set_memory_valid(unsigned long addr, int numpages, int enable); int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +bool kernel_page_present(struct page *page); #include <asm-generic/cacheflush.h> diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h index 4c5bae7ca01c..d690b08dff2a 100644 --- a/arch/riscv/include/asm/set_memory.h +++ b/arch/riscv/include/asm/set_memory.h @@ -24,6 +24,7 @@ static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +bool kernel_page_present(struct page *page); #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c index 321b09d2e2ea..87ba5a68bbb8 100644 --- a/arch/riscv/mm/pageattr.c +++ b/arch/riscv/mm/pageattr.c @@ -198,3 +198,32 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) __pgprot(0), __pgprot(_PAGE_PRESENT)); } #endif + +bool kernel_page_present(struct page *page) +{ + unsigned long addr = (unsigned long)page_address(page); + pgd_t *pgd; + pud_t *pud; + p4d_t *p4d; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset_k(addr); + if (!pgd_present(*pgd)) + return false; + + p4d = p4d_offset(pgd, addr); + if (!p4d_present(*p4d)) + return false; + + pud = pud_offset(p4d, addr); + if (!pud_present(*pud)) + return false; + + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + return false; + + pte = pte_offset_kernel(pmd, addr); + return pte_present(*pte); +} diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h index 5948218f35c5..4352f08bfbb5 100644 --- a/arch/x86/include/asm/set_memory.h +++ b/arch/x86/include/asm/set_memory.h @@ -82,6 +82,7 @@ int set_pages_rw(struct page *page, int numpages); int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +bool kernel_page_present(struct page *page); extern int kernel_set_to_readonly; diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 7f248fc45317..16f878c26667 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -2228,7 +2228,6 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) } #endif /* CONFIG_DEBUG_PAGEALLOC */ -#ifdef CONFIG_HIBERNATION bool kernel_page_present(struct page *page) { unsigned int level; @@ -2240,7 +2239,6 @@ bool kernel_page_present(struct page *page) pte = lookup_address((unsigned long)page_address(page), &level); return (pte_val(*pte) & _PAGE_PRESENT); } -#endif /* CONFIG_HIBERNATION */ int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, unsigned numpages, unsigned long page_flags) diff --git a/include/linux/mm.h b/include/linux/mm.h index ab0ef6bd351d..44b82f22e76a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2937,16 +2937,9 @@ static inline void debug_pagealloc_map_pages(struct page *page, if (debug_pagealloc_enabled_static()) __kernel_map_pages(page, numpages, enable); } - -#ifdef CONFIG_HIBERNATION -extern bool kernel_page_present(struct page *page); -#endif /* CONFIG_HIBERNATION */ #else /* CONFIG_DEBUG_PAGEALLOC */ static inline void debug_pagealloc_map_pages(struct page *page, int numpages, int enable) {} -#ifdef CONFIG_HIBERNATION -static inline bool kernel_page_present(struct page *page) { return true; } -#endif /* CONFIG_HIBERNATION */ #endif /* CONFIG_DEBUG_PAGEALLOC */ #ifdef __HAVE_ARCH_GATE_AREA diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h index 860e0f843c12..fe1aa4e54680 100644 --- a/include/linux/set_memory.h +++ b/include/linux/set_memory.h @@ -23,6 +23,11 @@ static inline int set_direct_map_default_noflush(struct page *page) { return 0; } + +static inline bool kernel_page_present(struct page *page) +{ + return true; +} #endif #ifndef set_mce_nospec