diff options
Diffstat (limited to 'mm/huge_memory.c')
-rw-r--r-- | mm/huge_memory.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 610e3df2768a..cca80d96e509 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -1278,64 +1278,90 @@ out: | |||
1278 | int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | 1278 | int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, |
1279 | unsigned long addr, pmd_t pmd, pmd_t *pmdp) | 1279 | unsigned long addr, pmd_t pmd, pmd_t *pmdp) |
1280 | { | 1280 | { |
1281 | struct anon_vma *anon_vma = NULL; | ||
1281 | struct page *page; | 1282 | struct page *page; |
1282 | unsigned long haddr = addr & HPAGE_PMD_MASK; | 1283 | unsigned long haddr = addr & HPAGE_PMD_MASK; |
1284 | int page_nid = -1, this_nid = numa_node_id(); | ||
1283 | int target_nid; | 1285 | int target_nid; |
1284 | int current_nid = -1; | 1286 | bool page_locked; |
1285 | bool migrated; | 1287 | bool migrated = false; |
1286 | 1288 | ||
1287 | spin_lock(&mm->page_table_lock); | 1289 | spin_lock(&mm->page_table_lock); |
1288 | if (unlikely(!pmd_same(pmd, *pmdp))) | 1290 | if (unlikely(!pmd_same(pmd, *pmdp))) |
1289 | goto out_unlock; | 1291 | goto out_unlock; |
1290 | 1292 | ||
1291 | page = pmd_page(pmd); | 1293 | page = pmd_page(pmd); |
1292 | get_page(page); | 1294 | page_nid = page_to_nid(page); |
1293 | current_nid = page_to_nid(page); | ||
1294 | count_vm_numa_event(NUMA_HINT_FAULTS); | 1295 | count_vm_numa_event(NUMA_HINT_FAULTS); |
1295 | if (current_nid == numa_node_id()) | 1296 | if (page_nid == this_nid) |
1296 | count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL); | 1297 | count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL); |
1297 | 1298 | ||
1299 | /* | ||
1300 | * Acquire the page lock to serialise THP migrations but avoid dropping | ||
1301 | * page_table_lock if at all possible | ||
1302 | */ | ||
1303 | page_locked = trylock_page(page); | ||
1298 | target_nid = mpol_misplaced(page, vma, haddr); | 1304 | target_nid = mpol_misplaced(page, vma, haddr); |
1299 | if (target_nid == -1) { | 1305 | if (target_nid == -1) { |
1300 | put_page(page); | 1306 | /* If the page was locked, there are no parallel migrations */ |
1301 | goto clear_pmdnuma; | 1307 | if (page_locked) |
1308 | goto clear_pmdnuma; | ||
1309 | |||
1310 | /* | ||
1311 | * Otherwise wait for potential migrations and retry. We do | ||
1312 | * relock and check_same as the page may no longer be mapped. | ||
1313 | * As the fault is being retried, do not account for it. | ||
1314 | */ | ||
1315 | spin_unlock(&mm->page_table_lock); | ||
1316 | wait_on_page_locked(page); | ||
1317 | page_nid = -1; | ||
1318 | goto out; | ||
1302 | } | 1319 | } |
1303 | 1320 | ||
1304 | /* Acquire the page lock to serialise THP migrations */ | 1321 | /* Page is misplaced, serialise migrations and parallel THP splits */ |
1322 | get_page(page); | ||
1305 | spin_unlock(&mm->page_table_lock); | 1323 | spin_unlock(&mm->page_table_lock); |
1306 | lock_page(page); | 1324 | if (!page_locked) |
1325 | lock_page(page); | ||
1326 | anon_vma = page_lock_anon_vma_read(page); | ||
1307 | 1327 | ||
1308 | /* Confirm the PTE did not while locked */ | 1328 | /* Confirm the PTE did not while locked */ |
1309 | spin_lock(&mm->page_table_lock); | 1329 | spin_lock(&mm->page_table_lock); |
1310 | if (unlikely(!pmd_same(pmd, *pmdp))) { | 1330 | if (unlikely(!pmd_same(pmd, *pmdp))) { |
1311 | unlock_page(page); | 1331 | unlock_page(page); |
1312 | put_page(page); | 1332 | put_page(page); |
1333 | page_nid = -1; | ||
1313 | goto out_unlock; | 1334 | goto out_unlock; |
1314 | } | 1335 | } |
1315 | spin_unlock(&mm->page_table_lock); | ||
1316 | 1336 | ||
1317 | /* Migrate the THP to the requested node */ | 1337 | /* |
1338 | * Migrate the THP to the requested node, returns with page unlocked | ||
1339 | * and pmd_numa cleared. | ||
1340 | */ | ||
1341 | spin_unlock(&mm->page_table_lock); | ||
1318 | migrated = migrate_misplaced_transhuge_page(mm, vma, | 1342 | migrated = migrate_misplaced_transhuge_page(mm, vma, |
1319 | pmdp, pmd, addr, page, target_nid); | 1343 | pmdp, pmd, addr, page, target_nid); |
1320 | if (!migrated) | 1344 | if (migrated) |
1321 | goto check_same; | 1345 | page_nid = target_nid; |
1322 | |||
1323 | task_numa_fault(target_nid, HPAGE_PMD_NR, true); | ||
1324 | return 0; | ||
1325 | 1346 | ||
1326 | check_same: | 1347 | goto out; |
1327 | spin_lock(&mm->page_table_lock); | ||
1328 | if (unlikely(!pmd_same(pmd, *pmdp))) | ||
1329 | goto out_unlock; | ||
1330 | clear_pmdnuma: | 1348 | clear_pmdnuma: |
1349 | BUG_ON(!PageLocked(page)); | ||
1331 | pmd = pmd_mknonnuma(pmd); | 1350 | pmd = pmd_mknonnuma(pmd); |
1332 | set_pmd_at(mm, haddr, pmdp, pmd); | 1351 | set_pmd_at(mm, haddr, pmdp, pmd); |
1333 | VM_BUG_ON(pmd_numa(*pmdp)); | 1352 | VM_BUG_ON(pmd_numa(*pmdp)); |
1334 | update_mmu_cache_pmd(vma, addr, pmdp); | 1353 | update_mmu_cache_pmd(vma, addr, pmdp); |
1354 | unlock_page(page); | ||
1335 | out_unlock: | 1355 | out_unlock: |
1336 | spin_unlock(&mm->page_table_lock); | 1356 | spin_unlock(&mm->page_table_lock); |
1337 | if (current_nid != -1) | 1357 | |
1338 | task_numa_fault(current_nid, HPAGE_PMD_NR, false); | 1358 | out: |
1359 | if (anon_vma) | ||
1360 | page_unlock_anon_vma_read(anon_vma); | ||
1361 | |||
1362 | if (page_nid != -1) | ||
1363 | task_numa_fault(page_nid, HPAGE_PMD_NR, migrated); | ||
1364 | |||
1339 | return 0; | 1365 | return 0; |
1340 | } | 1366 | } |
1341 | 1367 | ||