diff --git a/mm/mmap.c b/mm/mmap.c index 6df3e778e749..f6dd36674ab3 100755 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -3955,11 +3956,172 @@ static int reserve_mem_notifier(struct notifier_block *nb, return NOTIFY_OK; } +static void vmi_iter_initialize(struct vma_iterator *vmi, struct mm_struct *mm, + unsigned long start) +{ + struct ma_state *mas = &vmi->mas; + + memset(vmi, 0, sizeof(*vmi)); + mas->tree = &mm->mm_mt; + mas->index = start; + mas->node = MAS_START; +} + +static void dump_mt_vma(struct vm_area_struct *vma) +{ + pr_info("[VMA]: [0x%10lx-0x%10lx]\n", vma->vm_start, vma->vm_end); +} + +struct snapshot_vma { + unsigned long vm_start, vm_end, entry; +}; + +struct snapshot_vma snapshot_vmas[] = { + { 0x0000000000, 0x0000ffffff, 0x0000000000000000 }, + { 0x0001000000, 0x0001000fff, 0xffffff8008c35c80 }, + { 0x0001001000, 0x0001001fff, 0xffffff8008c354b0 }, + { 0x0001002000, 0x0001002fff, 0xffffff800a17d3e8 }, + { 0x0001003000, 0x0001003fff, 0xffffff800a17d898 }, + { 0x0001004000, 0x0001004fff, 0xffffff800a17daf0 }, + { 0x0001005000, 0x0001005fff, 0xffffff800a17d708 }, + { 0x0001006000, 0x0001006fff, 0xffffff800a17d7d0 }, + { 0x0001007000, 0x0001007fff, 0xffffff800a17d320 }, + { 0x0001008000, 0x0001008fff, 0xffffff800a17d578 }, + { 0x0001009000, 0x0001009fff, 0xffffff800a17d258 }, + { 0x000100a000, 0x000100afff, 0xffffff800a17de10 }, + { 0x000100b000, 0x000100bfff, 0xffffff800a17dbb8 }, + { 0x000100c000, 0x000100cfff, 0xffffff800a17d190 }, + /* merge_prev index 15 */ + { 0x000100d000, 0x000100dfff, 0xffffff800a17ded8 }, + /* index 16 */ + { 0x000100e000, 0x5580a2ffff, 0x0000000000000000 }, + { 0x5580a30000, 0x5580a30fff, 0xffffff8008c353e8 }, + { 0x5580a31000, 0x5580a4efff, 0x0000000000000000 }, + { 0x5580a4f000, 0x5580a4ffff, 0xffffff8008c350c8 }, + { 0x5580a50000, 0x5580a50fff, 0xffffff8008c35ed8 }, + { 0x5580a51000, 0x5580c4afff, 0x0000000000000000 }, + { 0x5580c4b000, 0x5580c6bfff, 0xffffff8008c35708 }, + { 0x5580c6c000, 0x7f880cffff, 0x0000000000000000 }, + { 0x7f880d0000, 0x7f88257fff, 0xffffff8008d80000 }, + { 0x7f88258000, 0x7f8826bfff, 0xffffff8008d807d0 }, + { 0x7f8826c000, 0x7f8826ffff, 0xffffff8008c904b0 }, + { 0x7f88270000, 0x7f88271fff, 0xffffff8008c90bb8 }, + { 0x7f88272000, 0x7f8827efff, 0xffffff8008c90578 }, + { 0x7f8827f000, 0x7f8827ffff, 0x0000000000000000 }, + { 0x7f88280000, 0x7f88293fff, 0xffffff8008c4aa28 }, + { 0x7f88294000, 0x7f882aefff, 0xffffff8008c4a4b0 }, + { 0x7f882af000, 0x7f882affff, 0xffffff8008c35a28 }, + { 0x7f882b0000, 0x7f882b0fff, 0xffffff8008c903e8 }, + { 0x7f882b1000, 0x7f882bffff, 0x0000000000000000 }, + { 0x7f882c0000, 0x7f8833ffff, 0xffffff8008c35d48 }, + { 0x7f88340000, 0x7f8834efff, 0xffffff8008c35000 }, + { 0x7f8834f000, 0x7f8834ffff, 0xffffff8008c35640 }, + { 0x7f88350000, 0x7f88350fff, 0xffffff8008c907d0 }, + { 0x7f88351000, 0x7f8835ffff, 0x0000000000000000 }, + { 0x7f88360000, 0x7f8855afff, 0xffffff8008c35af0 }, + { 0x7f8855b000, 0x7f88564fff, 0xffffff8008c35320 }, + { 0x7f88565000, 0x7f8856ffff, 0xffffff8008c35190 }, + { 0x7f88570000, 0x7f88572fff, 0xffffff8008c90708 }, + { 0x7f88573000, 0x7f88575fff, 0xffffff8008c357d0 }, + { 0x7f88576000, 0x7f88584fff, 0x0000000000000000 }, + { 0x7f88585000, 0x7f885abfff, 0xffffff8008c35bb8 }, + { 0x7f885ac000, 0x7f885b3fff, 0x0000000000000000 }, + { 0x7f885b4000, 0x7f885b7fff, 0xffffff8008c90d48 }, + { 0x7f885b8000, 0x7f885bdfff, 0x0000000000000000 }, + { 0x7f885be000, 0x7f885bffff, 0xffffff8008c35258 }, + { 0x7f885c0000, 0x7f885c1fff, 0xffffff8008c35578 }, + { 0x7f885c2000, 0x7f885c2fff, 0xffffff8008c35898 }, + { 0x7f885c3000, 0x7f885c4fff, 0xffffff8008c35e10 }, + { 0x7f885c5000, 0x7f885c6fff, 0xffffff8008c35960 }, + { 0x7f885c7000, 0x7fda32bfff, 0x0000000000000000 }, + { 0x7fda32c000, 0x7fda34cfff, 0xffffff800940dc80 }, + { 0x7fda34d000, 0xffffffffffffff, 0000000000000000 }, +}; + +#define MERGE_INX (15) +static int maple_test_merge_proc_show(struct seq_file *m, void *v) +{ + struct vma_iterator vmi; + struct mm_struct *mm; + struct snapshot_vma *snapshot_vma; + struct vm_area_struct *vmas, *vma, *prev_vma; + int snapshot_len = ARRAY_SIZE(snapshot_vmas); + int i; + + mm = kmalloc(sizeof(*mm), GFP_KERNEL | __GFP_NOFAIL); + vmas = kmalloc_array(snapshot_len, sizeof(struct vm_area_struct), + GFP_KERNEL | __GFP_NOFAIL); + BUG_ON(!mm || !vmas); + mt_init_flags(&mm->mm_mt, MM_MT_FLAGS); + + for (i = 0; i < snapshot_len; i++) { + snapshot_vma = snapshot_vmas + i; + vma = vmas + i; + /* gap */ + if (!snapshot_vma->entry) + continue; + + vma->vm_start = snapshot_vma->vm_start; + vma->vm_end = snapshot_vma->vm_end + 1; + + /* mma_region */ + vmi_iter_initialize(&vmi, mm, vma->vm_start); + vma_iter_config(&vmi, vma->vm_start, vma->vm_end); + if (vma_iter_prealloc(&vmi, vma)) + BUG_ON(true); + vma_iter_store(&vmi, vma); + } + + /* + * 1. mock __mmap_region() + * the new_vma: [0x100e000-0x100f000] + */ + snapshot_vma = snapshot_vmas + MERGE_INX; + vma->vm_start = snapshot_vma->vm_start; + vma->vm_end = snapshot_vma->vm_start + 0x1000; + dump_mt_vma(vma); + vmi_iter_initialize(&vmi, mm, vma->vm_start); + vma_iter_config(&vmi, vma->vm_start, vma->vm_end); + + /* + * 2. mock vma_iter_prealloc() + * in __mmap_region() + */ + if (vma_iter_prealloc(&vmi, vma)) + BUG_ON(true); + + /* + * 3. mock vma_merge() + * the new_vma can be merged with prev_vma [0x100d000-0x100e000] + */ + prev_vma = vma_prev(&vmi); + prev_vma->vm_end = vma->vm_end; + dump_mt_vma(prev_vma); + vma_iter_config(&vmi, prev_vma->vm_start, prev_vma->vm_end); + + /* + * 4. mock vma_iter_prealloc() + * in vma_merge(); + */ + if (vma_iter_prealloc(&vmi, prev_vma)) + BUG_ON(true); + + /* + * 5. panic here + */ + vma_iter_store(&vmi, prev_vma); + __mt_destroy(&mm->mm_mt); + kfree(mm); + kfree(vmas); + return 0; +} + static int __meminit init_reserve_notifier(void) { if (hotplug_memory_notifier(reserve_mem_notifier, DEFAULT_CALLBACK_PRI)) pr_err("Failed registering memory add/remove notifier for admin reserve\n"); + proc_create_single("maple_test_merge", 0, NULL, maple_test_merge_proc_show); return 0; } subsys_initcall(init_reserve_notifier);