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

mm: page migration use migration entry for swapcache too

Hitherto page migration has avoided using a migration entry for a
swapcache page mapped into userspace, apparently for historical reasons.
So any page blessed with swapcache would entail a minor fault when it's
next touched, which page migration otherwise tries to avoid. Swapcache in
an mlocked area is rare, so won't often matter, but still better fixed.

Just rearrange the block in try_to_unmap_one(), to handle TTU_MIGRATION
before checking PageAnon, that's all (apart from some reindenting).

Well, no, that's not quite all: doesn't this by the way fix a soft_dirty
bug, that page migration of a file page was forgetting to transfer the
soft_dirty bit? Probably not a serious bug: if I understand correctly,
soft_dirty afficionados usually have to handle file pages separately
anyway; but we publish the bit in /proc/<pid>/pagemap on file mappings as
well as anonymous, so page migration ought not to perturb it.

Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reviewed-by: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Hugh Dickins and committed by
Linus Torvalds
470f119f 03f15c86

+33 -36
+33 -36
mm/rmap.c
··· 1379 1379 dec_mm_counter(mm, MM_ANONPAGES); 1380 1380 else 1381 1381 dec_mm_counter(mm, MM_FILEPAGES); 1382 - } else if (PageAnon(page)) { 1383 - swp_entry_t entry = { .val = page_private(page) }; 1382 + } else if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATION)) { 1383 + swp_entry_t entry; 1384 1384 pte_t swp_pte; 1385 - 1386 - if (PageSwapCache(page)) { 1387 - /* 1388 - * Store the swap location in the pte. 1389 - * See handle_pte_fault() ... 1390 - */ 1391 - if (swap_duplicate(entry) < 0) { 1392 - set_pte_at(mm, address, pte, pteval); 1393 - ret = SWAP_FAIL; 1394 - goto out_unmap; 1395 - } 1396 - if (list_empty(&mm->mmlist)) { 1397 - spin_lock(&mmlist_lock); 1398 - if (list_empty(&mm->mmlist)) 1399 - list_add(&mm->mmlist, &init_mm.mmlist); 1400 - spin_unlock(&mmlist_lock); 1401 - } 1402 - dec_mm_counter(mm, MM_ANONPAGES); 1403 - inc_mm_counter(mm, MM_SWAPENTS); 1404 - } else if (IS_ENABLED(CONFIG_MIGRATION)) { 1405 - /* 1406 - * Store the pfn of the page in a special migration 1407 - * pte. do_swap_page() will wait until the migration 1408 - * pte is removed and then restart fault handling. 1409 - */ 1410 - BUG_ON(!(flags & TTU_MIGRATION)); 1411 - entry = make_migration_entry(page, pte_write(pteval)); 1412 - } 1385 + /* 1386 + * Store the pfn of the page in a special migration 1387 + * pte. do_swap_page() will wait until the migration 1388 + * pte is removed and then restart fault handling. 1389 + */ 1390 + entry = make_migration_entry(page, pte_write(pteval)); 1413 1391 swp_pte = swp_entry_to_pte(entry); 1414 1392 if (pte_soft_dirty(pteval)) 1415 1393 swp_pte = pte_swp_mksoft_dirty(swp_pte); 1416 1394 set_pte_at(mm, address, pte, swp_pte); 1417 - } else if (IS_ENABLED(CONFIG_MIGRATION) && 1418 - (flags & TTU_MIGRATION)) { 1419 - /* Establish migration entry for a file page */ 1420 - swp_entry_t entry; 1421 - entry = make_migration_entry(page, pte_write(pteval)); 1422 - set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); 1395 + } else if (PageAnon(page)) { 1396 + swp_entry_t entry = { .val = page_private(page) }; 1397 + pte_t swp_pte; 1398 + /* 1399 + * Store the swap location in the pte. 1400 + * See handle_pte_fault() ... 1401 + */ 1402 + VM_BUG_ON_PAGE(!PageSwapCache(page), page); 1403 + if (swap_duplicate(entry) < 0) { 1404 + set_pte_at(mm, address, pte, pteval); 1405 + ret = SWAP_FAIL; 1406 + goto out_unmap; 1407 + } 1408 + if (list_empty(&mm->mmlist)) { 1409 + spin_lock(&mmlist_lock); 1410 + if (list_empty(&mm->mmlist)) 1411 + list_add(&mm->mmlist, &init_mm.mmlist); 1412 + spin_unlock(&mmlist_lock); 1413 + } 1414 + dec_mm_counter(mm, MM_ANONPAGES); 1415 + inc_mm_counter(mm, MM_SWAPENTS); 1416 + swp_pte = swp_entry_to_pte(entry); 1417 + if (pte_soft_dirty(pteval)) 1418 + swp_pte = pte_swp_mksoft_dirty(swp_pte); 1419 + set_pte_at(mm, address, pte, swp_pte); 1423 1420 } else 1424 1421 dec_mm_counter(mm, MM_FILEPAGES); 1425 1422