path: root/mm
diff options
authorHugh Dickins <>2021-06-24 18:39:52 -0700
committerLinus Torvalds <>2021-06-24 19:40:54 -0700
commitfe19bd3dae3d15d2fbfdb3de8839a6ea0fe94264 (patch)
treefab0cfb0af57acaa2ece48ca74d5cf2964b10862 /mm
parent5fa54346caf67b4b1b10b1f390316ae466da4d53 (diff)
mm, futex: fix shared futex pgoff on shmem huge page
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. [ give hugetlb_basepage_index() prototype the correct scope] Link: Fixes: 800d8c63b2e9 ("shmem: add huge pages support") Reported-by: Neel Natu <> Signed-off-by: Hugh Dickins <> Reviewed-by: Matthew Wilcox (Oracle) <> Acked-by: Thomas Gleixner <> Cc: "Kirill A. Shutemov" <> Cc: Zhang Yi <> Cc: Mel Gorman <> Cc: Mike Kravetz <> Cc: Ingo Molnar <> Cc: Peter Zijlstra <> Cc: Darren Hart <> Cc: Davidlohr Bueso <> Cc: <> Signed-off-by: Andrew Morton <> Signed-off-by: Linus Torvalds <>
Diffstat (limited to 'mm')
1 files changed, 1 insertions, 4 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index e0a5f9cbbece..5ba5a0da6d57 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1588,15 +1588,12 @@ struct address_space *hugetlb_page_mapping_lock_write(struct page *hpage)
return NULL;
-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);