]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mm: add !pte_present() check on existing hugetlb_entry callbacks
authorNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Thu, 22 May 2014 00:42:43 +0000 (10:42 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 22 May 2014 00:42:43 +0000 (10:42 +1000)
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 <sasha.levin@oracle.com>
Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: <stable@vger.kernel.org> [3.12+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/proc/task_mmu.c
mm/mempolicy.c

index a310a763ee3990a110e5b63492d0812f76c5057a..4cceb910156fc4930992df591cd80e51a368eca0 100644 (file)
@@ -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;
index af635c458dee71f9924ad1735bc4e3110dec0d97..9d2ef4111a4c10c3f4b6368444d8e440796da799 100644 (file)
@@ -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;