| From 0d777df5d8953293be090d9ab5a355db893e8357 Mon Sep 17 00:00:00 2001 |
| From: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> |
| Date: Fri, 11 Dec 2015 13:40:49 -0800 |
| Subject: mm: hugetlb: call huge_pte_alloc() only if ptep is null |
| |
| commit 0d777df5d8953293be090d9ab5a355db893e8357 upstream. |
| |
| Currently at the beginning of hugetlb_fault(), we call huge_pte_offset() |
| and check whether the obtained *ptep is a migration/hwpoison entry or |
| not. And if not, then we get to call huge_pte_alloc(). This is racy |
| because the *ptep could turn into migration/hwpoison entry after the |
| huge_pte_offset() check. This race results in BUG_ON in |
| huge_pte_alloc(). |
| |
| We don't have to call huge_pte_alloc() when the huge_pte_offset() |
| returns non-NULL, so let's fix this bug with moving the code into else |
| block. |
| |
| Note that the *ptep could turn into a migration/hwpoison entry after |
| this block, but that's not a problem because we have another |
| !pte_present check later (we never go into hugetlb_no_page() in that |
| case.) |
| |
| Fixes: 290408d4a250 ("hugetlb: hugepage migration core") |
| Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> |
| Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com> |
| Acked-by: David Rientjes <rientjes@google.com> |
| Cc: Hugh Dickins <hughd@google.com> |
| Cc: Dave Hansen <dave.hansen@intel.com> |
| Cc: Mel Gorman <mgorman@suse.de> |
| Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> |
| Cc: Mike Kravetz <mike.kravetz@oracle.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| [lizf: Backported to 3.4: adjust context] |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| mm/hugetlb.c | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/mm/hugetlb.c |
| +++ b/mm/hugetlb.c |
| @@ -2835,12 +2835,12 @@ int hugetlb_fault(struct mm_struct *mm, |
| } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) |
| return VM_FAULT_HWPOISON_LARGE | |
| VM_FAULT_SET_HINDEX(h - hstates); |
| + } else { |
| + ptep = huge_pte_alloc(mm, address, huge_page_size(h)); |
| + if (!ptep) |
| + return VM_FAULT_OOM; |
| } |
| |
| - ptep = huge_pte_alloc(mm, address, huge_page_size(h)); |
| - if (!ptep) |
| - return VM_FAULT_OOM; |
| - |
| /* |
| * Serialize hugepage allocation and instantiation, so that we don't |
| * get spurious allocation failures if two CPUs race to instantiate |