diff --git a/include/linux/mm.h b/include/linux/mm.h index b8ed44f401b5..f83a1c9ec8e4 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3091,6 +3091,16 @@ static inline bool gup_must_unshare(unsigned int flags, struct page *page) if (IS_ENABLED(CONFIG_HAVE_FAST_GUP)) smp_rmb(); + /* + * During GUP-fast we might not get called on the head page for a + * hugetlb page that is mapped using cont-PTE, because GUP-fast does + * not work with the abstracted hugetlb PTEs that always point at the + * head page. For hugetlb, PageAnonExclusive only applies on the head + * page (as it cannot be partially COW-shared), so lookup the head page. + */ + if (unlikely(!PageHead(page) && PageHuge(page))) + page = compound_head(page); + /* * Note that PageKsm() pages cannot be exclusive, and consequently, * cannot get pinned.