Skip to content

Commit 587fe58

Browse files
Mel GormanIngo Molnar
Mel Gorman
authored and
Ingo Molnar
committed
mm: Prevent parallel splits during THP migration
THP migrations are serialised by the page lock but on its own that does not prevent THP splits. If the page is split during THP migration then the pmd_same checks will prevent page table corruption but the unlock page and other fix-ups potentially will cause corruption. This patch takes the anon_vma lock to prevent parallel splits during migration. Signed-off-by: Mel Gorman <[email protected]> Reviewed-by: Rik van Riel <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Srikar Dronamraju <[email protected]> Cc: <[email protected]> Signed-off-by: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 42836f5 commit 587fe58

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

mm/huge_memory.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,18 +1278,18 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
12781278
int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
12791279
unsigned long addr, pmd_t pmd, pmd_t *pmdp)
12801280
{
1281+
struct anon_vma *anon_vma = NULL;
12811282
struct page *page;
12821283
unsigned long haddr = addr & HPAGE_PMD_MASK;
12831284
int target_nid;
12841285
int current_nid = -1;
1285-
bool migrated;
1286+
bool migrated, page_locked;
12861287

12871288
spin_lock(&mm->page_table_lock);
12881289
if (unlikely(!pmd_same(pmd, *pmdp)))
12891290
goto out_unlock;
12901291

12911292
page = pmd_page(pmd);
1292-
get_page(page);
12931293
current_nid = page_to_nid(page);
12941294
count_vm_numa_event(NUMA_HINT_FAULTS);
12951295
if (current_nid == numa_node_id())
@@ -1299,12 +1299,29 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
12991299
* Acquire the page lock to serialise THP migrations but avoid dropping
13001300
* page_table_lock if at all possible
13011301
*/
1302-
if (trylock_page(page))
1303-
goto got_lock;
1302+
page_locked = trylock_page(page);
1303+
target_nid = mpol_misplaced(page, vma, haddr);
1304+
if (target_nid == -1) {
1305+
/* If the page was locked, there are no parallel migrations */
1306+
if (page_locked) {
1307+
unlock_page(page);
1308+
goto clear_pmdnuma;
1309+
}
13041310

1305-
/* Serialise against migrationa and check placement check placement */
1311+
/* Otherwise wait for potential migrations and retry fault */
1312+
spin_unlock(&mm->page_table_lock);
1313+
wait_on_page_locked(page);
1314+
goto out;
1315+
}
1316+
1317+
/* Page is misplaced, serialise migrations and parallel THP splits */
1318+
get_page(page);
13061319
spin_unlock(&mm->page_table_lock);
1307-
lock_page(page);
1320+
if (!page_locked) {
1321+
lock_page(page);
1322+
page_locked = true;
1323+
}
1324+
anon_vma = page_lock_anon_vma_read(page);
13081325

13091326
/* Confirm the PTE did not while locked */
13101327
spin_lock(&mm->page_table_lock);
@@ -1314,14 +1331,6 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
13141331
goto out_unlock;
13151332
}
13161333

1317-
got_lock:
1318-
target_nid = mpol_misplaced(page, vma, haddr);
1319-
if (target_nid == -1) {
1320-
unlock_page(page);
1321-
put_page(page);
1322-
goto clear_pmdnuma;
1323-
}
1324-
13251334
/* Migrate the THP to the requested node */
13261335
spin_unlock(&mm->page_table_lock);
13271336
migrated = migrate_misplaced_transhuge_page(mm, vma,
@@ -1330,6 +1339,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
13301339
goto check_same;
13311340

13321341
task_numa_fault(target_nid, HPAGE_PMD_NR, true);
1342+
if (anon_vma)
1343+
page_unlock_anon_vma_read(anon_vma);
13331344
return 0;
13341345

13351346
check_same:
@@ -1346,6 +1357,11 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
13461357
update_mmu_cache_pmd(vma, addr, pmdp);
13471358
out_unlock:
13481359
spin_unlock(&mm->page_table_lock);
1360+
1361+
out:
1362+
if (anon_vma)
1363+
page_unlock_anon_vma_read(anon_vma);
1364+
13491365
if (current_nid != -1)
13501366
task_numa_fault(current_nid, HPAGE_PMD_NR, false);
13511367
return 0;

0 commit comments

Comments
 (0)