|
@@ -1437,6 +1437,8 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
|
|
|
* We don't mlock() pte-mapped THPs. This way we can avoid
|
|
|
* leaking mlocked pages into non-VM_LOCKED VMAs.
|
|
|
*
|
|
|
+ * For anon THP:
|
|
|
+ *
|
|
|
* In most cases the pmd is the only mapping of the page as we
|
|
|
* break COW for the mlock() -- see gup_flags |= FOLL_WRITE for
|
|
|
* writable private mappings in populate_vma_page_range().
|
|
@@ -1444,15 +1446,26 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
|
|
|
* The only scenario when we have the page shared here is if we
|
|
|
* mlocking read-only mapping shared over fork(). We skip
|
|
|
* mlocking such pages.
|
|
|
+ *
|
|
|
+ * For file THP:
|
|
|
+ *
|
|
|
+ * We can expect PageDoubleMap() to be stable under page lock:
|
|
|
+ * for file pages we set it in page_add_file_rmap(), which
|
|
|
+ * requires page to be locked.
|
|
|
*/
|
|
|
- if (compound_mapcount(page) == 1 && !PageDoubleMap(page) &&
|
|
|
- page->mapping && trylock_page(page)) {
|
|
|
- lru_add_drain();
|
|
|
- if (page->mapping)
|
|
|
- mlock_vma_page(page);
|
|
|
- unlock_page(page);
|
|
|
- }
|
|
|
+
|
|
|
+ if (PageAnon(page) && compound_mapcount(page) != 1)
|
|
|
+ goto skip_mlock;
|
|
|
+ if (PageDoubleMap(page) || !page->mapping)
|
|
|
+ goto skip_mlock;
|
|
|
+ if (!trylock_page(page))
|
|
|
+ goto skip_mlock;
|
|
|
+ lru_add_drain();
|
|
|
+ if (page->mapping && !PageDoubleMap(page))
|
|
|
+ mlock_vma_page(page);
|
|
|
+ unlock_page(page);
|
|
|
}
|
|
|
+skip_mlock:
|
|
|
page += (addr & ~HPAGE_PMD_MASK) >> PAGE_SHIFT;
|
|
|
VM_BUG_ON_PAGE(!PageCompound(page), page);
|
|
|
if (flags & FOLL_GET)
|