The patch titled Subject: mm/rmap: fix old bug: munlocking THP missed other mlocks has been added to the -mm tree. Its filename is mm-rmap-fix-old-bug-munlocking-thp-missed-other-mlocks.patch This patch should soon appear at https://ozlabs.org/~akpm/mmots/broken-out/mm-rmap-fix-old-bug-munlocking-thp-missed-other-mlocks.patch and later at https://ozlabs.org/~akpm/mmotm/broken-out/mm-rmap-fix-old-bug-munlocking-thp-missed-other-mlocks.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Hugh Dickins <hughd@xxxxxxxxxx> Subject: mm/rmap: fix old bug: munlocking THP missed other mlocks The kernel recovers in due course from missing Mlocked pages: but there was no point in calling page_mlock() (formerly known as try_to_munlock()) on a THP, because nothing got done even when it was found to be mapped in another VM_LOCKED vma. It's true that we need to be careful: Mlocked accounting of pte-mapped THPs is too difficult (so consistently avoided); but Mlocked accounting of only-pmd-mapped file THPs is supposed to work, even when multiple mappings are mlocked and munlocked or munmapped. Refine the tests. Many thanks to Kirill for reminding that PageDoubleMap cannot be relied on to warn of pte mappings in the Anon THP case; and a scan of subpages does not seem appropriate here. Note how follow_trans_huge_pmd() does not even mark an Anon THP as mlocked when compound_mapcount != 1: multiple mlocking of Anon THP is avoided, so simply return from page_mlock() in this case. I said the kernel recovers: but would page reclaim be likely to split THP before rediscovering that it's VM_LOCKED? Apparently so. I have worked on a fix for that, but it's a different issue, and not something to rush. Whereas page_mlock_one() could not be reviewed without fixing this first. Link: https://lkml.kernel.org/r/6c4d46aa-4d73-76a7-bcce-a09024768f63@xxxxxxxxxx Fixes: 9a73f61bdb8a ("thp, mlock: do not mlock PTE-mapped file huge pages") Signed-off-by: Hugh Dickins <hughd@xxxxxxxxxx> Acked-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> Cc: Alistair Popple <apopple@xxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Jason Gunthorpe <jgg@xxxxxxxxxx> Cc: Ralph Campbell <rcampbell@xxxxxxxxxx> Cc: Shakeel Butt <shakeelb@xxxxxxxxxx> Cc: Yang Shi <shy828301@xxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- mm/rmap.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) --- a/mm/rmap.c~mm-rmap-fix-old-bug-munlocking-thp-missed-other-mlocks +++ a/mm/rmap.c @@ -1440,20 +1440,20 @@ static bool try_to_unmap_one(struct page /* * If the page is mlock()d, we cannot swap it out. */ - if (!(flags & TTU_IGNORE_MLOCK)) { - if (vma->vm_flags & VM_LOCKED) { - /* PTE-mapped THP are never mlocked */ - if (!PageTransCompound(page)) { - /* - * Holding pte lock, we do *not* need - * mmap_lock here - */ - mlock_vma_page(page); - } - ret = false; - page_vma_mapped_walk_done(&pvmw); - break; - } + if (!(flags & TTU_IGNORE_MLOCK) && + (vma->vm_flags & VM_LOCKED)) { + /* + * PTE-mapped THP are never marked as mlocked: so do + * not set it on a DoubleMap THP, nor on an Anon THP + * (which may still be PTE-mapped after DoubleMap was + * cleared). But stop unmapping even in those cases. + */ + if (!PageTransCompound(page) || (PageHead(page) && + !PageDoubleMap(page) && !PageAnon(page))) + mlock_vma_page(page); + page_vma_mapped_walk_done(&pvmw); + ret = false; + break; } /* Unexpected PMD-mapped THP? */ @@ -1984,9 +1984,13 @@ static bool page_mlock_one(struct page * * munlock_vma_pages_range(). */ if (vma->vm_flags & VM_LOCKED) { - /* PTE-mapped THP are never mlocked */ - if (!PageTransCompound(page)) - mlock_vma_page(page); + /* + * PTE-mapped THP are never marked as mlocked; but + * this function is never called on a DoubleMap THP, + * nor on an Anon THP (which may still be PTE-mapped + * after DoubleMap was cleared). + */ + mlock_vma_page(page); page_vma_mapped_walk_done(&pvmw); } @@ -2020,6 +2024,10 @@ void page_mlock(struct page *page) VM_BUG_ON_PAGE(!PageLocked(page) || PageLRU(page), page); VM_BUG_ON_PAGE(PageCompound(page) && PageDoubleMap(page), page); + /* Anon THP are only marked as mlocked when singly mapped */ + if (PageTransCompound(page) && PageAnon(page)) + return; + rmap_walk(page, &rwc); } _ Patches currently in -mm which might be from hughd@xxxxxxxxxx are mm-rmap-fix-comments-left-over-from-recent-changes.patch mm-rmap-fix-old-bug-munlocking-thp-missed-other-mlocks.patch mm-rmap-fix-new-bug-premature-return-from-page_mlock_one.patch mm-rmap-try_to_migrate-skip-zone_device-device_private.patch fs-mm-fix-race-in-unlinking-swapfile.patch