path: root/kernel
diff options
authorHugh Dickins <>2021-06-24 18:39:52 -0700
committerLinus Torvalds <>2021-06-24 19:40:54 -0700
commitfe19bd3dae3d15d2fbfdb3de8839a6ea0fe94264 (patch)
treefab0cfb0af57acaa2ece48ca74d5cf2964b10862 /kernel
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 'kernel')
1 files changed, 1 insertions, 2 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 4938a00bc785..408cad5e8968 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -35,7 +35,6 @@
#include <linux/jhash.h>
#include <linux/pagemap.h>
#include <linux/syscalls.h>
-#include <linux/hugetlb.h>
#include <linux/freezer.h>
#include <linux/memblock.h>
#include <linux/fault-inject.h>
@@ -650,7 +649,7 @@ again:
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);