lkml.org 
[lkml]   [2021]   [Jun]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 66/71] mm, futex: fix shared futex pgoff on shmem huge page
    Date
    From: Hugh Dickins <hughd@google.com>

    [ Upstream commit fe19bd3dae3d15d2fbfdb3de8839a6ea0fe94264 ]

    If more than one futex is placed on a shmem huge page, it can happen
    that waking the second wakes the first instead, and leaves the second
    waiting: the key's shared.pgoff is wrong.

    When 3.11 commit 13d60f4b6ab5 ("futex: Take hugepages into account when
    generating futex_key"), the only shared huge pages came from hugetlbfs,
    and the code added to deal with its exceptional page->index was put into
    hugetlb source. Then that was missed when 4.8 added shmem huge pages.

    page_to_pgoff() is what others use for this nowadays: except that, as
    currently written, it gives the right answer on hugetlbfs head, but
    nonsense on hugetlbfs tails. Fix that by calling hugetlbfs-specific
    hugetlb_basepage_index() on PageHuge tails as well as on head.

    Yes, it's unconventional to declare hugetlb_basepage_index() there in
    pagemap.h, rather than in hugetlb.h; but I do not expect anything but
    page_to_pgoff() ever to need it.

    [akpm@linux-foundation.org: give hugetlb_basepage_index() prototype the correct scope]

    Link: https://lkml.kernel.org/r/b17d946b-d09-326e-b42a-52884c36df32@google.com
    Fixes: 800d8c63b2e9 ("shmem: add huge pages support")
    Reported-by: Neel Natu <neelnatu@google.com>
    Signed-off-by: Hugh Dickins <hughd@google.com>
    Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
    Cc: Zhang Yi <wetpzy@gmail.com>
    Cc: Mel Gorman <mgorman@techsingularity.net>
    Cc: Mike Kravetz <mike.kravetz@oracle.com>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Darren Hart <dvhart@infradead.org>
    Cc: Davidlohr Bueso <dave@stgolabs.net>
    Cc: <stable@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

    Note on stable backport: leave redundant #include <linux/hugetlb.h>
    in kernel/futex.c, to avoid conflict over the header files included.

    Signed-off-by: Hugh Dickins <hughd@google.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    include/linux/hugetlb.h | 16 ----------------
    include/linux/pagemap.h | 13 +++++++------
    kernel/futex.c | 2 +-
    mm/hugetlb.c | 5 +----
    4 files changed, 9 insertions(+), 27 deletions(-)

    diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
    index fc717aeb2b3d..a0513c444446 100644
    --- a/include/linux/hugetlb.h
    +++ b/include/linux/hugetlb.h
    @@ -469,17 +469,6 @@ static inline int hstate_index(struct hstate *h)
    return h - hstates;
    }

    -pgoff_t __basepage_index(struct page *page);
    -
    -/* Return page->index in PAGE_SIZE units */
    -static inline pgoff_t basepage_index(struct page *page)
    -{
    - if (!PageCompound(page))
    - return page->index;
    -
    - return __basepage_index(page);
    -}
    -
    extern int dissolve_free_huge_page(struct page *page);
    extern int dissolve_free_huge_pages(unsigned long start_pfn,
    unsigned long end_pfn);
    @@ -695,11 +684,6 @@ static inline int hstate_index(struct hstate *h)
    return 0;
    }

    -static inline pgoff_t basepage_index(struct page *page)
    -{
    - return page->index;
    -}
    -
    static inline int dissolve_free_huge_page(struct page *page)
    {
    return 0;
    diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
    index 37a4d9e32cd3..8543b1aaa529 100644
    --- a/include/linux/pagemap.h
    +++ b/include/linux/pagemap.h
    @@ -397,7 +397,7 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
    }

    /*
    - * Get index of the page with in radix-tree
    + * Get index of the page within radix-tree (but not for hugetlb pages).
    * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE)
    */
    static inline pgoff_t page_to_index(struct page *page)
    @@ -416,15 +416,16 @@ static inline pgoff_t page_to_index(struct page *page)
    return pgoff;
    }

    +extern pgoff_t hugetlb_basepage_index(struct page *page);
    +
    /*
    - * Get the offset in PAGE_SIZE.
    - * (TODO: hugepage should have ->index in PAGE_SIZE)
    + * Get the offset in PAGE_SIZE (even for hugetlb pages).
    + * (TODO: hugetlb pages should have ->index in PAGE_SIZE)
    */
    static inline pgoff_t page_to_pgoff(struct page *page)
    {
    - if (unlikely(PageHeadHuge(page)))
    - return page->index << compound_order(page);
    -
    + if (unlikely(PageHuge(page)))
    + return hugetlb_basepage_index(page);
    return page_to_index(page);
    }

    diff --git a/kernel/futex.c b/kernel/futex.c
    index 375e7e98e301..f82879ae6577 100644
    --- a/kernel/futex.c
    +++ b/kernel/futex.c
    @@ -737,7 +737,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_a

    key->both.offset |= FUT_OFF_INODE; /* inode-based key */
    key->shared.i_seq = get_inode_sequence_number(inode);
    - key->shared.pgoff = basepage_index(tail);
    + key->shared.pgoff = page_to_pgoff(tail);
    rcu_read_unlock();
    }

    diff --git a/mm/hugetlb.c b/mm/hugetlb.c
    index fe15e7d8220a..95a32749af4d 100644
    --- a/mm/hugetlb.c
    +++ b/mm/hugetlb.c
    @@ -1461,15 +1461,12 @@ int PageHeadHuge(struct page *page_head)
    return get_compound_page_dtor(page_head) == free_huge_page;
    }

    -pgoff_t __basepage_index(struct page *page)
    +pgoff_t hugetlb_basepage_index(struct page *page)
    {
    struct page *page_head = compound_head(page);
    pgoff_t index = page_index(page_head);
    unsigned long compound_idx;

    - if (!PageHuge(page_head))
    - return page_index(page);
    -
    if (compound_order(page_head) >= MAX_ORDER)
    compound_idx = page_to_pfn(page) - page_to_pfn(page_head);
    else
    --
    2.30.2
    \
     
     \ /
      Last update: 2021-06-28 16:49    [W:4.215 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site