aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2013-10-07 06:28:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-12 22:05:34 -0500
commit299723f2297726ca4c0a9d8ef3548ece5466431d (patch)
tree77b40fd4d5eaecf1e7ebbacded33baf60bb3d7f0 /mm
parent2e39395e03fe936171a8b45894cbf75ccfae0375 (diff)
mm: Prevent parallel splits during THP migration
commit 587fe586f44a48f9691001ba6c45b86c8e4ba21f upstream. 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 <mgorman@suse.de> Reviewed-by: Rik van Riel <riel@redhat.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1381141781-10992-7-git-send-email-mgorman@suse.de Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/huge_memory.c44
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:
1288int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, 1288int 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
1327got_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
1345check_same: 1356check_same:
@@ -1356,6 +1367,11 @@ clear_pmdnuma:
1356 update_mmu_cache_pmd(vma, addr, pmdp); 1367 update_mmu_cache_pmd(vma, addr, pmdp);
1357out_unlock: 1368out_unlock:
1358 spin_unlock(&mm->page_table_lock); 1369 spin_unlock(&mm->page_table_lock);
1370
1371out:
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;