From: Naoya Horiguchi Date: Thu, 22 May 2014 00:42:43 +0000 (+1000) Subject: mm: add !pte_present() check on existing hugetlb_entry callbacks X-Git-Tag: next-20140530~2^2~386 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=3863b7ea2d73aff25266cc19ef971fdb668a4ce5;p=karo-tx-linux.git mm: add !pte_present() check on existing hugetlb_entry callbacks Page table walker doesn't check non-present hugetlb entry in common path, so hugetlb_entry() callbacks must check it. The reason for this behavior is that some callers want to handle it in its own way. However, some callers don't check it now, which causes unpredictable result, for example when we have a race between migrating hugepage and reading /proc/pid/numa_maps. This patch fixes it by adding !pte_present checks on buggy callbacks. This bug exists for years and got visible by introducing hugepage migration. ChangeLog v2: - fix if condition (check !pte_present() instead of pte_present()) Reported-by: Sasha Levin Signed-off-by: Naoya Horiguchi Cc: Rik van Riel Cc: [3.12+] Signed-off-by: Andrew Morton --- diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index a310a763ee39..4cceb910156f 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1300,6 +1300,9 @@ static int gather_hugetlb_stats(pte_t *pte, unsigned long addr, if (pte_none(*pte)) return 0; + if (!pte_present(*pte)) + return 0; + page = pte_page(*pte); if (!page) return 0; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index af635c458dee..9d2ef4111a4c 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -524,8 +524,12 @@ static int queue_pages_hugetlb(pte_t *pte, unsigned long addr, unsigned long flags = qp->flags; int nid; struct page *page; + pte_t entry; - page = pte_page(huge_ptep_get(pte)); + entry = huge_ptep_get(pte); + if (!pte_present(entry)) + return 0; + page = pte_page(entry); nid = page_to_nid(page); if (node_isset(nid, *qp->nmask) == !!(flags & MPOL_MF_INVERT)) return 0;