Web lists-archives.com

[PATCH v1] mm: migrate: fix remove_migration_pte() for ksm pages




I found that calling page migration for ksm pages causes the following bug:

    [49467.651804] page:ffffea0004d51180 count:2 mapcount:2 mapping:ffff88013c785141 index:0x913
    [49467.652565] flags: 0x57ffffc0040068(uptodate|lru|active|swapbacked)
    [49467.653115] raw: 0057ffffc0040068 ffff88013c785141 0000000000000913 0000000200000001
    [49467.653762] raw: ffffea0004d5f9e0 ffffea0004d53f60 0000000000000000 ffff88007d81b800
    [49467.654399] page dumped because: VM_BUG_ON_PAGE(!PageLocked(page))
    [49467.654910] page->mem_cgroup:ffff88007d81b800
    [49467.655278] ------------[ cut here ]------------
    [49467.655665] kernel BUG at /src/linux-dev/mm/rmap.c:1086!
    [49467.656102] invalid opcode: 0000 [#1] SMP
    [49467.656451] Modules linked in: ppdev parport_pc virtio_balloon i2c_piix4 pcspkr parport i2c_core acpi_cpufreq ip_tables xfs libcrc32c ata_generic pata_acpi ata_piix 8139too libata virtio_blk 8139cp crc32c_intel mii virtio_pci virtio_ring serio_raw virtio floppy dm_mirror dm_region_hash dm_log dm_mod
    [49467.658653] CPU: 0 PID: 3162 Comm: bash Not tainted 4.11.0-rc2-mm1+ #1
    [49467.659188] Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
    [49467.659863] task: ffff88007a20ad00 task.stack: ffffc90002470000
    [49467.660367] RIP: 0010:do_page_add_anon_rmap+0x1ba/0x260
    [49467.660806] RSP: 0018:ffffc90002473b30 EFLAGS: 00010282
    [49467.661331] RAX: 0000000000000021 RBX: ffffea0004d51180 RCX: 0000000000000006
    [49467.661916] RDX: 0000000000000000 RSI: 0000000000000082 RDI: ffff88007dc0dfe0
    [49467.662502] RBP: ffffc90002473b58 R08: 00000000fffffffe R09: 00000000000001c1
    [49467.663085] R10: 0000000000000005 R11: 00000000000001c0 R12: ffff880139ab3d80
    [49467.663696] R13: 0000000000000000 R14: 0000700000000200 R15: 0000160000000000
    [49467.664282] FS:  00007f5195f50740(0000) GS:ffff88007dc00000(0000) knlGS:0000000000000000
    [49467.664950] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    [49467.665426] CR2: 00007fd450287000 CR3: 000000007a08e000 CR4: 00000000001406f0
    [49467.666011] Call Trace:
    [49467.666221]  page_add_anon_rmap+0x18/0x20
    [49467.666573]  remove_migration_pte+0x220/0x2c0
    [49467.666937]  rmap_walk_ksm+0x143/0x220
    [49467.667250]  rmap_walk+0x55/0x60
    [49467.667526]  remove_migration_ptes+0x53/0x80
    [49467.667883]  ? numamigrate_update_ratelimit+0x110/0x110
    [49467.668319]  migrate_pages+0x8ed/0xb60
    [49467.668635]  ? kill_proc.isra.17+0x150/0x150
    [49467.668992]  soft_offline_page+0x309/0x8d0
    [49467.669341]  store_soft_offline_page+0xaf/0xf0
    [49467.669711]  dev_attr_store+0x18/0x30
    [49467.670020]  sysfs_kf_write+0x3a/0x50
    [49467.670330]  kernfs_fop_write+0xff/0x180
    [49467.670657]  __vfs_write+0x37/0x160
    [49467.670951]  ? _cond_resched+0x19/0x30
    [49467.671265]  ? __fd_install+0x31/0xd0
    [49467.671589]  ? _cond_resched+0x19/0x30
    [49467.671904]  vfs_write+0xb2/0x1b0
    [49467.672185]  ? syscall_trace_enter+0x1d0/0x2b0
    [49467.672559]  SyS_write+0x55/0xc0
    [49467.672832]  do_syscall_64+0x67/0x180
    [49467.673139]  entry_SYSCALL64_slow_path+0x25/0x25
    [49467.673525] RIP: 0033:0x7f51956339e0
    [49467.673824] RSP: 002b:00007ffcfa0dffc8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
    [49467.674447] RAX: ffffffffffffffda RBX: 000000000000000c RCX: 00007f51956339e0
    [49467.675031] RDX: 000000000000000c RSI: 00007f5195f53000 RDI: 0000000000000001
    [49467.675620] RBP: 00007f5195f53000 R08: 000000000000000a R09: 00007f5195f50740
    [49467.676206] R10: 000000000000000b R11: 0000000000000246 R12: 00007f5195907400
    [49467.676807] R13: 000000000000000c R14: 0000000000000001 R15: 0000000000000000
    [49467.677394] Code: fe ff ff 48 81 c2 00 02 00 00 48 89 55 d8 e8 2e c3 fd ff 48 8b 55 d8 e9 42 ff ff ff 48 c7 c6 e0 52 a1 81 48 89 df e8 46 ad fe ff <0f> 0b 48 83 e8 01 e9 7f fe ff ff 48 83 e8 01 e9 96 fe ff ff 48
    [49467.678944] RIP: do_page_add_anon_rmap+0x1ba/0x260 RSP: ffffc90002473b30
    [49467.680102] ---[ end trace a679d00f4af2df48 ]---
    [49467.680495] Kernel panic - not syncing: Fatal exception
    [49467.680943] Kernel Offset: disabled
    [49467.681237] ---[ end Kernel panic - not syncing: Fatal exception

The problem is in the following lines:

    new = page - pvmw.page->index +
        linear_page_index(vma, pvmw.address);

The 'new' is calculated with 'page' which is given by the caller as a
destination page and some offset adjustment for thp.
But this doesn't properly work for ksm pages because pvmw.page->index
doesn't change for each address but linear_page_index() changes, which
means that 'new' points to different pages for each addresses backed
by the ksm page. As a result, we try to set totally unrelated pages
as destination pages, and that causes kernel crash.

This patch fixes the miscalculation and makes ksm page migration work fine.

Fixes: 3fe87967c536 ("mm: convert remove_migration_pte() to use page_vma_mapped_walk()")
Signed-off-by: Naoya Horiguchi <n-horiguchi@xxxxxxxxxxxxx>
---
 mm/migrate.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git v4.11-rc2-mmotm-2017-03-14-15-41/mm/migrate.c v4.11-rc2-mmotm-2017-03-14-15-41_patched/mm/migrate.c
index e0cb4b7..937378e 100644
--- v4.11-rc2-mmotm-2017-03-14-15-41/mm/migrate.c
+++ v4.11-rc2-mmotm-2017-03-14-15-41_patched/mm/migrate.c
@@ -209,8 +209,11 @@ static int remove_migration_pte(struct page *page, struct vm_area_struct *vma,
 
 	VM_BUG_ON_PAGE(PageTail(page), page);
 	while (page_vma_mapped_walk(&pvmw)) {
-		new = page - pvmw.page->index +
-			linear_page_index(vma, pvmw.address);
+		if (PageKsm(page))
+			new = page;
+		else
+			new = page - pvmw.page->index +
+				linear_page_index(vma, pvmw.address);
 
 		get_page(new);
 		pte = pte_mkold(mk_pte(new, READ_ONCE(vma->vm_page_prot)));
-- 
2.7.0