Commit 500d65d471018d9a13b0d51b7e141ed2a3555c1d
Committed by
Linus Torvalds
1 parent
0af4e98b6b
Exists in
master
and in
4 other branches
thp: pmd_trans_huge migrate bugcheck
No pmd_trans_huge should ever materialize in migration ptes areas, because we split the hugepage before migration ptes are instantiated. Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 12 additions and 1 deletions Side-by-side Diff
include/linux/mm.h
... | ... | @@ -1490,6 +1490,7 @@ |
1490 | 1490 | #define FOLL_DUMP 0x08 /* give error on hole if it would be zero */ |
1491 | 1491 | #define FOLL_FORCE 0x10 /* get_user_pages read/write w/o permission */ |
1492 | 1492 | #define FOLL_MLOCK 0x40 /* mark page as mlocked */ |
1493 | +#define FOLL_SPLIT 0x80 /* don't return transhuge pages, split them */ | |
1493 | 1494 | |
1494 | 1495 | typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, |
1495 | 1496 | void *data); |
mm/memory.c
... | ... | @@ -1305,6 +1305,10 @@ |
1305 | 1305 | goto out; |
1306 | 1306 | } |
1307 | 1307 | if (pmd_trans_huge(*pmd)) { |
1308 | + if (flags & FOLL_SPLIT) { | |
1309 | + split_huge_page_pmd(mm, pmd); | |
1310 | + goto split_fallthrough; | |
1311 | + } | |
1308 | 1312 | spin_lock(&mm->page_table_lock); |
1309 | 1313 | if (likely(pmd_trans_huge(*pmd))) { |
1310 | 1314 | if (unlikely(pmd_trans_splitting(*pmd))) { |
... | ... | @@ -1320,6 +1324,7 @@ |
1320 | 1324 | spin_unlock(&mm->page_table_lock); |
1321 | 1325 | /* fall through */ |
1322 | 1326 | } |
1327 | +split_fallthrough: | |
1323 | 1328 | if (unlikely(pmd_bad(*pmd))) |
1324 | 1329 | goto no_page_table; |
1325 | 1330 |
mm/migrate.c
... | ... | @@ -113,6 +113,8 @@ |
113 | 113 | goto out; |
114 | 114 | |
115 | 115 | pmd = pmd_offset(pud, addr); |
116 | + if (pmd_trans_huge(*pmd)) | |
117 | + goto out; | |
116 | 118 | if (!pmd_present(*pmd)) |
117 | 119 | goto out; |
118 | 120 | |
... | ... | @@ -632,6 +634,9 @@ |
632 | 634 | /* page was freed from under us. So we are done. */ |
633 | 635 | goto move_newpage; |
634 | 636 | } |
637 | + if (unlikely(PageTransHuge(page))) | |
638 | + if (unlikely(split_huge_page(page))) | |
639 | + goto move_newpage; | |
635 | 640 | |
636 | 641 | /* prepare cgroup just returns 0 or -ENOMEM */ |
637 | 642 | rc = -EAGAIN; |
... | ... | @@ -1063,7 +1068,7 @@ |
1063 | 1068 | if (!vma || pp->addr < vma->vm_start || !vma_migratable(vma)) |
1064 | 1069 | goto set_status; |
1065 | 1070 | |
1066 | - page = follow_page(vma, pp->addr, FOLL_GET); | |
1071 | + page = follow_page(vma, pp->addr, FOLL_GET|FOLL_SPLIT); | |
1067 | 1072 | |
1068 | 1073 | err = PTR_ERR(page); |
1069 | 1074 | if (IS_ERR(page)) |