Skip to content

Commit 3b77e8c

Browse files
Hugh Dickinstorvalds
authored andcommitted
mm/thp: make is_huge_zero_pmd() safe and quicker
Most callers of is_huge_zero_pmd() supply a pmd already verified present; but a few (notably zap_huge_pmd()) do not - it might be a pmd migration entry, in which the pfn is encoded differently from a present pmd: which might pass the is_huge_zero_pmd() test (though not on x86, since L1TF forced us to protect against that); or perhaps even crash in pmd_page() applied to a swap-like entry. Make it safe by adding pmd_present() check into is_huge_zero_pmd() itself; and make it quicker by saving huge_zero_pfn, so that is_huge_zero_pmd() will not need to do that pmd_page() lookup each time. __split_huge_pmd_locked() checked pmd_trans_huge() before: that worked, but is unnecessary now that is_huge_zero_pmd() checks present. Link: https://lkml.kernel.org/r/[email protected] Fixes: e71769a ("mm: enable thp migration for shmem thp") Signed-off-by: Hugh Dickins <[email protected]> Acked-by: Kirill A. Shutemov <[email protected]> Reviewed-by: Yang Shi <[email protected]> Cc: Alistair Popple <[email protected]> Cc: Jan Kara <[email protected]> Cc: Jue Wang <[email protected]> Cc: "Matthew Wilcox (Oracle)" <[email protected]> Cc: Miaohe Lin <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: Peter Xu <[email protected]> Cc: Ralph Campbell <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Wang Yugui <[email protected]> Cc: Zi Yan <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 99fa8a4 commit 3b77e8c

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

include/linux/huge_mm.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ struct page *follow_devmap_pud(struct vm_area_struct *vma, unsigned long addr,
286286
vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t orig_pmd);
287287

288288
extern struct page *huge_zero_page;
289+
extern unsigned long huge_zero_pfn;
289290

290291
static inline bool is_huge_zero_page(struct page *page)
291292
{
@@ -294,7 +295,7 @@ static inline bool is_huge_zero_page(struct page *page)
294295

295296
static inline bool is_huge_zero_pmd(pmd_t pmd)
296297
{
297-
return is_huge_zero_page(pmd_page(pmd));
298+
return READ_ONCE(huge_zero_pfn) == pmd_pfn(pmd) && pmd_present(pmd);
298299
}
299300

300301
static inline bool is_huge_zero_pud(pud_t pud)
@@ -440,6 +441,11 @@ static inline bool is_huge_zero_page(struct page *page)
440441
return false;
441442
}
442443

444+
static inline bool is_huge_zero_pmd(pmd_t pmd)
445+
{
446+
return false;
447+
}
448+
443449
static inline bool is_huge_zero_pud(pud_t pud)
444450
{
445451
return false;

mm/huge_memory.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static struct shrinker deferred_split_shrinker;
6262

6363
static atomic_t huge_zero_refcount;
6464
struct page *huge_zero_page __read_mostly;
65+
unsigned long huge_zero_pfn __read_mostly = ~0UL;
6566

6667
bool transparent_hugepage_enabled(struct vm_area_struct *vma)
6768
{
@@ -98,6 +99,7 @@ static bool get_huge_zero_page(void)
9899
__free_pages(zero_page, compound_order(zero_page));
99100
goto retry;
100101
}
102+
WRITE_ONCE(huge_zero_pfn, page_to_pfn(zero_page));
101103

102104
/* We take additional reference here. It will be put back by shrinker */
103105
atomic_set(&huge_zero_refcount, 2);
@@ -147,6 +149,7 @@ static unsigned long shrink_huge_zero_page_scan(struct shrinker *shrink,
147149
if (atomic_cmpxchg(&huge_zero_refcount, 1, 0) == 1) {
148150
struct page *zero_page = xchg(&huge_zero_page, NULL);
149151
BUG_ON(zero_page == NULL);
152+
WRITE_ONCE(huge_zero_pfn, ~0UL);
150153
__free_pages(zero_page, compound_order(zero_page));
151154
return HPAGE_PMD_NR;
152155
}
@@ -2071,7 +2074,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
20712074
return;
20722075
}
20732076

2074-
if (pmd_trans_huge(*pmd) && is_huge_zero_pmd(*pmd)) {
2077+
if (is_huge_zero_pmd(*pmd)) {
20752078
/*
20762079
* FIXME: Do we want to invalidate secondary mmu by calling
20772080
* mmu_notifier_invalidate_range() see comments below inside

0 commit comments

Comments
 (0)