Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: migrate: check page_count of THP before migrating

Hugh Dickins pointed out that migrate_misplaced_transhuge_page() does
not check page_count before migrating like base page migration and
khugepage. He could not see why this was safe and he is right.

The potential impact of the bug is avoided due to the limitations of
NUMA balancing. The page_mapcount() check ensures that only a single
address space is using this page and as THPs are typically private it
should not be possible for another address space to fault it in
parallel. If the address space has one associated task then it's
difficult to have both a GUP pin and be referencing the page at the same
time. If there are multiple tasks then a buggy scenario requires that
another thread be accessing the page while the direct IO is in flight.
This is dodgy behaviour as there is a possibility of corruption with or
without THP migration. It would be

While we happen to be safe for the most part it is shoddy to depend on
such "safety" so this patch checks the page count similar to anonymous
pages. Note that this does not mean that the page_mapcount() check can
go away. If we were to remove the page_mapcount() check the the THP
would have to be unmapped from all referencing PTEs, replaced with
migration PTEs and restored properly afterwards.

Signed-off-by: Mel Gorman <mgorman@suse.de>
Reported-by: Hugh Dickins <hughd@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Acked-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Mel Gorman and committed by
Linus Torvalds
04fa5d6a 0a1af1d6

+13 -1
+13 -1
mm/migrate.c
··· 1679 1679 page_xchg_last_nid(new_page, page_last_nid(page)); 1680 1680 1681 1681 isolated = numamigrate_isolate_page(pgdat, page); 1682 - if (!isolated) { 1682 + 1683 + /* 1684 + * Failing to isolate or a GUP pin prevents migration. The expected 1685 + * page count is 2. 1 for anonymous pages without a mapping and 1 1686 + * for the callers pin. If the page was isolated, the page will 1687 + * need to be put back on the LRU. 1688 + */ 1689 + if (!isolated || page_count(page) != 2) { 1683 1690 count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR); 1684 1691 put_page(new_page); 1692 + if (isolated) { 1693 + putback_lru_page(page); 1694 + isolated = 0; 1695 + goto out; 1696 + } 1685 1697 goto out_keep_locked; 1686 1698 } 1687 1699