From 8bcfd8b451b619d0c00acac6f23c4c1102400b78 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 22 Feb 2013 16:36:07 -0800 Subject: [PATCH] --- yaml --- r: 356630 b: refs/heads/master c: 5117b3b835f288314a2d4e5512bc1747e3a7c8ed h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/include/linux/mm.h | 1 + trunk/mm/ksm.c | 2 +- trunk/mm/memory.c | 20 ++++++++++++++++++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/[refs] b/[refs] index 24a5c8c5cb8a..36ab4690383d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: bc56620b493496b8a6962080b644ccc537f4d526 +refs/heads/master: 5117b3b835f288314a2d4e5512bc1747e3a7c8ed diff --git a/trunk/include/linux/mm.h b/trunk/include/linux/mm.h index 6124f1db50fe..e7c3f9a0111a 100644 --- a/trunk/include/linux/mm.h +++ b/trunk/include/linux/mm.h @@ -1651,6 +1651,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma, #define FOLL_SPLIT 0x80 /* don't return transhuge pages, split them */ #define FOLL_HWPOISON 0x100 /* check page is hwpoisoned */ #define FOLL_NUMA 0x200 /* force NUMA hinting page fault */ +#define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); diff --git a/trunk/mm/ksm.c b/trunk/mm/ksm.c index 0320327b8a6c..d61cba6fa1dc 100644 --- a/trunk/mm/ksm.c +++ b/trunk/mm/ksm.c @@ -364,7 +364,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr) do { cond_resched(); - page = follow_page(vma, addr, FOLL_GET); + page = follow_page(vma, addr, FOLL_GET | FOLL_MIGRATION); if (IS_ERR_OR_NULL(page)) break; if (PageKsm(page)) diff --git a/trunk/mm/memory.c b/trunk/mm/memory.c index 5d2ef1217d0c..ec8ba011fa7d 100644 --- a/trunk/mm/memory.c +++ b/trunk/mm/memory.c @@ -1548,8 +1548,24 @@ struct page *follow_page_mask(struct vm_area_struct *vma, ptep = pte_offset_map_lock(mm, pmd, address, &ptl); pte = *ptep; - if (!pte_present(pte)) - goto no_page; + if (!pte_present(pte)) { + swp_entry_t entry; + /* + * KSM's break_ksm() relies upon recognizing a ksm page + * even while it is being migrated, so for that case we + * need migration_entry_wait(). + */ + if (likely(!(flags & FOLL_MIGRATION))) + goto no_page; + if (pte_none(pte) || pte_file(pte)) + goto no_page; + entry = pte_to_swp_entry(pte); + if (!is_migration_entry(entry)) + goto no_page; + pte_unmap_unlock(ptep, ptl); + migration_entry_wait(mm, pmd, address); + goto split_fallthrough; + } if ((flags & FOLL_NUMA) && pte_numa(pte)) goto no_page; if ((flags & FOLL_WRITE) && !pte_write(pte))