diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/huge_memory.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 0ad946974df4..64f8aadb0595 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -1288,18 +1288,18 @@ out: | |||
1288 | int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | 1288 | int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, |
1289 | unsigned long addr, pmd_t pmd, pmd_t *pmdp) | 1289 | unsigned long addr, pmd_t pmd, pmd_t *pmdp) |
1290 | { | 1290 | { |
1291 | struct anon_vma *anon_vma = NULL; | ||
1291 | struct page *page; | 1292 | struct page *page; |
1292 | unsigned long haddr = addr & HPAGE_PMD_MASK; | 1293 | unsigned long haddr = addr & HPAGE_PMD_MASK; |
1293 | int target_nid; | 1294 | int target_nid; |
1294 | int current_nid = -1; | 1295 | int current_nid = -1; |
1295 | bool migrated; | 1296 | bool migrated, page_locked; |
1296 | 1297 | ||
1297 | spin_lock(&mm->page_table_lock); | 1298 | spin_lock(&mm->page_table_lock); |
1298 | if (unlikely(!pmd_same(pmd, *pmdp))) | 1299 | if (unlikely(!pmd_same(pmd, *pmdp))) |
1299 | goto out_unlock; | 1300 | goto out_unlock; |
1300 | 1301 | ||
1301 | page = pmd_page(pmd); | 1302 | page = pmd_page(pmd); |
1302 | get_page(page); | ||
1303 | current_nid = page_to_nid(page); | 1303 | current_nid = page_to_nid(page); |
1304 | count_vm_numa_event(NUMA_HINT_FAULTS); | 1304 | count_vm_numa_event(NUMA_HINT_FAULTS); |
1305 | if (current_nid == numa_node_id()) | 1305 | if (current_nid == numa_node_id()) |
@@ -1309,12 +1309,29 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1309 | * Acquire the page lock to serialise THP migrations but avoid dropping | 1309 | * Acquire the page lock to serialise THP migrations but avoid dropping |
1310 | * page_table_lock if at all possible | 1310 | * page_table_lock if at all possible |
1311 | */ | 1311 | */ |
1312 | if (trylock_page(page)) | 1312 | page_locked = trylock_page(page); |
1313 | goto got_lock; | 1313 | target_nid = mpol_misplaced(page, vma, haddr); |
1314 | if (target_nid == -1) { | ||
1315 | /* If the page was locked, there are no parallel migrations */ | ||
1316 | if (page_locked) { | ||
1317 | unlock_page(page); | ||
1318 | goto clear_pmdnuma; | ||
1319 | } | ||
1314 | 1320 | ||
1315 | /* Serialise against migrationa and check placement check placement */ | 1321 | /* Otherwise wait for potential migrations and retry fault */ |
1322 | spin_unlock(&mm->page_table_lock); | ||
1323 | wait_on_page_locked(page); | ||
1324 | goto out; | ||
1325 | } | ||
1326 | |||
1327 | /* Page is misplaced, serialise migrations and parallel THP splits */ | ||
1328 | get_page(page); | ||
1316 | spin_unlock(&mm->page_table_lock); | 1329 | spin_unlock(&mm->page_table_lock); |
1317 | lock_page(page); | 1330 | if (!page_locked) { |
1331 | lock_page(page); | ||
1332 | page_locked = true; | ||
1333 | } | ||
1334 | anon_vma = page_lock_anon_vma_read(page); | ||
1318 | 1335 | ||
1319 | /* Confirm the PTE did not while locked */ | 1336 | /* Confirm the PTE did not while locked */ |
1320 | spin_lock(&mm->page_table_lock); | 1337 | spin_lock(&mm->page_table_lock); |
@@ -1324,14 +1341,6 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1324 | goto out_unlock; | 1341 | goto out_unlock; |
1325 | } | 1342 | } |
1326 | 1343 | ||
1327 | got_lock: | ||
1328 | target_nid = mpol_misplaced(page, vma, haddr); | ||
1329 | if (target_nid == -1) { | ||
1330 | unlock_page(page); | ||
1331 | put_page(page); | ||
1332 | goto clear_pmdnuma; | ||
1333 | } | ||
1334 | |||
1335 | /* Migrate the THP to the requested node */ | 1344 | /* Migrate the THP to the requested node */ |
1336 | spin_unlock(&mm->page_table_lock); | 1345 | spin_unlock(&mm->page_table_lock); |
1337 | migrated = migrate_misplaced_transhuge_page(mm, vma, | 1346 | migrated = migrate_misplaced_transhuge_page(mm, vma, |
@@ -1340,6 +1349,8 @@ got_lock: | |||
1340 | goto check_same; | 1349 | goto check_same; |
1341 | 1350 | ||
1342 | task_numa_fault(target_nid, HPAGE_PMD_NR, true); | 1351 | task_numa_fault(target_nid, HPAGE_PMD_NR, true); |
1352 | if (anon_vma) | ||
1353 | page_unlock_anon_vma_read(anon_vma); | ||
1343 | return 0; | 1354 | return 0; |
1344 | 1355 | ||
1345 | check_same: | 1356 | check_same: |
@@ -1356,6 +1367,11 @@ clear_pmdnuma: | |||
1356 | update_mmu_cache_pmd(vma, addr, pmdp); | 1367 | update_mmu_cache_pmd(vma, addr, pmdp); |
1357 | out_unlock: | 1368 | out_unlock: |
1358 | spin_unlock(&mm->page_table_lock); | 1369 | spin_unlock(&mm->page_table_lock); |
1370 | |||
1371 | out: | ||
1372 | if (anon_vma) | ||
1373 | page_unlock_anon_vma_read(anon_vma); | ||
1374 | |||
1359 | if (current_nid != -1) | 1375 | if (current_nid != -1) |
1360 | task_numa_fault(current_nid, HPAGE_PMD_NR, false); | 1376 | task_numa_fault(current_nid, HPAGE_PMD_NR, false); |
1361 | return 0; | 1377 | return 0; |