lkml.org 
[lkml]   [2017]   [Oct]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 174/192] mm: thp: fix SMP race condition between THP page fault and MADV_DONTNEED
    3.16.49-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Andrea Arcangeli <aarcange@redhat.com>

    commit ad33bb04b2a6cee6c1f99fabb15cddbf93ff0433 upstream.

    pmd_trans_unstable()/pmd_none_or_trans_huge_or_clear_bad() were
    introduced to locklessy (but atomically) detect when a pmd is a regular
    (stable) pmd or when the pmd is unstable and can infinitely transition
    from pmd_none() and pmd_trans_huge() from under us, while only holding
    the mmap_sem for reading (for writing not).

    While holding the mmap_sem only for reading, MADV_DONTNEED can run from
    under us and so before we can assume the pmd to be a regular stable pmd
    we need to compare it against pmd_none() and pmd_trans_huge() in an
    atomic way, with pmd_trans_unstable(). The old pmd_trans_huge() left a
    tiny window for a race.

    Useful applications are unlikely to notice the difference as doing
    MADV_DONTNEED concurrently with a page fault would lead to undefined
    behavior.

    [akpm@linux-foundation.org: tidy up comment grammar/layout]
    Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
    Reported-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    [js] 3.12 backport: no pmd_devmap in 3.12 yet.
    Signed-off-by: Jiri Slaby <jslaby@suse.cz>
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    mm/memory.c | 14 ++++++++++++--
    1 file changed, 12 insertions(+), 2 deletions(-)

    --- a/mm/memory.c
    +++ b/mm/memory.c
    @@ -3274,8 +3274,18 @@ static int __handle_mm_fault(struct mm_s
    if (unlikely(pmd_none(*pmd)) &&
    unlikely(__pte_alloc(mm, vma, pmd, address)))
    return VM_FAULT_OOM;
    - /* if an huge pmd materialized from under us just retry later */
    - if (unlikely(pmd_trans_huge(*pmd)))
    + /*
    + * If a huge pmd materialized under us just retry later. Use
    + * pmd_trans_unstable() instead of pmd_trans_huge() to ensure the pmd
    + * didn't become pmd_trans_huge under us and then back to pmd_none, as
    + * a result of MADV_DONTNEED running immediately after a huge pmd fault
    + * in a different thread of this mm, in turn leading to a misleading
    + * pmd_trans_huge() retval. All we have to ensure is that it is a
    + * regular pmd that we can walk with pte_offset_map() and we can do that
    + * through an atomic read in C, which is what pmd_trans_unstable()
    + * provides.
    + */
    + if (unlikely(pmd_trans_unstable(pmd)))
    return 0;
    /*
    * A regular pmd is established and it can't morph into a huge pmd
    \
     
     \ /
      Last update: 2017-10-09 16:00    [W:4.022 / U:1.152 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site