summaryrefslogtreecommitdiffstats
path: root/mm/migrate.c
diff options
context:
space:
mode:
authorJérôme Glisse <jglisse@redhat.com>2017-09-08 19:12:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-08 21:26:46 -0400
commit8c3328f1f36a5efe817ad4e06497af601936a460 (patch)
tree27c738203a3703c54cfb1e3bc018414480d2b767 /mm/migrate.c
parent8763cb45ab967a92a5ee49e9c544c0f0ea90e2d6 (diff)
mm/migrate: migrate_vma() unmap page from vma while collecting pages
Common case for migration of virtual address range is page are map only once inside the vma in which migration is taking place. Because we already walk the CPU page table for that range we can directly do the unmap there and setup special migration swap entry. Link: http://lkml.kernel.org/r/20170817000548.32038-16-jglisse@redhat.com Signed-off-by: Jérôme Glisse <jglisse@redhat.com> Signed-off-by: Evgeny Baskakov <ebaskakov@nvidia.com> Signed-off-by: John Hubbard <jhubbard@nvidia.com> Signed-off-by: Mark Hairgrove <mhairgrove@nvidia.com> Signed-off-by: Sherry Cheung <SCheung@nvidia.com> Signed-off-by: Subhash Gutti <sgutti@nvidia.com> Cc: Aneesh Kumar <aneesh.kumar@linux.vnet.ibm.com> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Dan Williams <dan.j.williams@intel.com> Cc: David Nellans <dnellans@nvidia.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Michal Hocko <mhocko@kernel.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Ross Zwisler <ross.zwisler@linux.intel.com> Cc: Vladimir Davydov <vdavydov.dev@gmail.com> Cc: Bob Liu <liubo95@huawei.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/migrate.c')
-rw-r--r--mm/migrate.c141
1 files changed, 112 insertions, 29 deletions
diff --git a/mm/migrate.c b/mm/migrate.c
index 991e8886093f..652b2c642eed 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2149,7 +2149,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
2149 struct migrate_vma *migrate = walk->private; 2149 struct migrate_vma *migrate = walk->private;
2150 struct vm_area_struct *vma = walk->vma; 2150 struct vm_area_struct *vma = walk->vma;
2151 struct mm_struct *mm = vma->vm_mm; 2151 struct mm_struct *mm = vma->vm_mm;
2152 unsigned long addr = start; 2152 unsigned long addr = start, unmapped = 0;
2153 spinlock_t *ptl; 2153 spinlock_t *ptl;
2154 pte_t *ptep; 2154 pte_t *ptep;
2155 2155
@@ -2194,9 +2194,12 @@ again:
2194 return migrate_vma_collect_hole(start, end, walk); 2194 return migrate_vma_collect_hole(start, end, walk);
2195 2195
2196 ptep = pte_offset_map_lock(mm, pmdp, addr, &ptl); 2196 ptep = pte_offset_map_lock(mm, pmdp, addr, &ptl);
2197 arch_enter_lazy_mmu_mode();
2198
2197 for (; addr < end; addr += PAGE_SIZE, ptep++) { 2199 for (; addr < end; addr += PAGE_SIZE, ptep++) {
2198 unsigned long mpfn, pfn; 2200 unsigned long mpfn, pfn;
2199 struct page *page; 2201 struct page *page;
2202 swp_entry_t entry;
2200 pte_t pte; 2203 pte_t pte;
2201 2204
2202 pte = *ptep; 2205 pte = *ptep;
@@ -2228,11 +2231,44 @@ again:
2228 mpfn = migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE; 2231 mpfn = migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE;
2229 mpfn |= pte_write(pte) ? MIGRATE_PFN_WRITE : 0; 2232 mpfn |= pte_write(pte) ? MIGRATE_PFN_WRITE : 0;
2230 2233
2234 /*
2235 * Optimize for the common case where page is only mapped once
2236 * in one process. If we can lock the page, then we can safely
2237 * set up a special migration page table entry now.
2238 */
2239 if (trylock_page(page)) {
2240 pte_t swp_pte;
2241
2242 mpfn |= MIGRATE_PFN_LOCKED;
2243 ptep_get_and_clear(mm, addr, ptep);
2244
2245 /* Setup special migration page table entry */
2246 entry = make_migration_entry(page, pte_write(pte));
2247 swp_pte = swp_entry_to_pte(entry);
2248 if (pte_soft_dirty(pte))
2249 swp_pte = pte_swp_mksoft_dirty(swp_pte);
2250 set_pte_at(mm, addr, ptep, swp_pte);
2251
2252 /*
2253 * This is like regular unmap: we remove the rmap and
2254 * drop page refcount. Page won't be freed, as we took
2255 * a reference just above.
2256 */
2257 page_remove_rmap(page, false);
2258 put_page(page);
2259 unmapped++;
2260 }
2261
2231next: 2262next:
2232 migrate->src[migrate->npages++] = mpfn; 2263 migrate->src[migrate->npages++] = mpfn;
2233 } 2264 }
2265 arch_leave_lazy_mmu_mode();
2234 pte_unmap_unlock(ptep - 1, ptl); 2266 pte_unmap_unlock(ptep - 1, ptl);
2235 2267
2268 /* Only flush the TLB if we actually modified any entries */
2269 if (unmapped)
2270 flush_tlb_range(walk->vma, start, end);
2271
2236 return 0; 2272 return 0;
2237} 2273}
2238 2274
@@ -2257,7 +2293,13 @@ static void migrate_vma_collect(struct migrate_vma *migrate)
2257 mm_walk.mm = migrate->vma->vm_mm; 2293 mm_walk.mm = migrate->vma->vm_mm;
2258 mm_walk.private = migrate; 2294 mm_walk.private = migrate;
2259 2295
2296 mmu_notifier_invalidate_range_start(mm_walk.mm,
2297 migrate->start,
2298 migrate->end);
2260 walk_page_range(migrate->start, migrate->end, &mm_walk); 2299 walk_page_range(migrate->start, migrate->end, &mm_walk);
2300 mmu_notifier_invalidate_range_end(mm_walk.mm,
2301 migrate->start,
2302 migrate->end);
2261 2303
2262 migrate->end = migrate->start + (migrate->npages << PAGE_SHIFT); 2304 migrate->end = migrate->start + (migrate->npages << PAGE_SHIFT);
2263} 2305}
@@ -2305,32 +2347,37 @@ static bool migrate_vma_check_page(struct page *page)
2305static void migrate_vma_prepare(struct migrate_vma *migrate) 2347static void migrate_vma_prepare(struct migrate_vma *migrate)
2306{ 2348{
2307 const unsigned long npages = migrate->npages; 2349 const unsigned long npages = migrate->npages;
2350 const unsigned long start = migrate->start;
2351 unsigned long addr, i, restore = 0;
2308 bool allow_drain = true; 2352 bool allow_drain = true;
2309 unsigned long i;
2310 2353
2311 lru_add_drain(); 2354 lru_add_drain();
2312 2355
2313 for (i = 0; (i < npages) && migrate->cpages; i++) { 2356 for (i = 0; (i < npages) && migrate->cpages; i++) {
2314 struct page *page = migrate_pfn_to_page(migrate->src[i]); 2357 struct page *page = migrate_pfn_to_page(migrate->src[i]);
2358 bool remap = true;
2315 2359
2316 if (!page) 2360 if (!page)
2317 continue; 2361 continue;
2318 2362
2319 /* 2363 if (!(migrate->src[i] & MIGRATE_PFN_LOCKED)) {
2320 * Because we are migrating several pages there can be 2364 /*
2321 * a deadlock between 2 concurrent migration where each 2365 * Because we are migrating several pages there can be
2322 * are waiting on each other page lock. 2366 * a deadlock between 2 concurrent migration where each
2323 * 2367 * are waiting on each other page lock.
2324 * Make migrate_vma() a best effort thing and backoff 2368 *
2325 * for any page we can not lock right away. 2369 * Make migrate_vma() a best effort thing and backoff
2326 */ 2370 * for any page we can not lock right away.
2327 if (!trylock_page(page)) { 2371 */
2328 migrate->src[i] = 0; 2372 if (!trylock_page(page)) {
2329 migrate->cpages--; 2373 migrate->src[i] = 0;
2330 put_page(page); 2374 migrate->cpages--;
2331 continue; 2375 put_page(page);
2376 continue;
2377 }
2378 remap = false;
2379 migrate->src[i] |= MIGRATE_PFN_LOCKED;
2332 } 2380 }
2333 migrate->src[i] |= MIGRATE_PFN_LOCKED;
2334 2381
2335 if (!PageLRU(page) && allow_drain) { 2382 if (!PageLRU(page) && allow_drain) {
2336 /* Drain CPU's pagevec */ 2383 /* Drain CPU's pagevec */
@@ -2339,21 +2386,50 @@ static void migrate_vma_prepare(struct migrate_vma *migrate)
2339 } 2386 }
2340 2387
2341 if (isolate_lru_page(page)) { 2388 if (isolate_lru_page(page)) {
2342 migrate->src[i] = 0; 2389 if (remap) {
2343 unlock_page(page); 2390 migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
2344 migrate->cpages--; 2391 migrate->cpages--;
2345 put_page(page); 2392 restore++;
2393 } else {
2394 migrate->src[i] = 0;
2395 unlock_page(page);
2396 migrate->cpages--;
2397 put_page(page);
2398 }
2346 continue; 2399 continue;
2347 } 2400 }
2348 2401
2349 if (!migrate_vma_check_page(page)) { 2402 if (!migrate_vma_check_page(page)) {
2350 migrate->src[i] = 0; 2403 if (remap) {
2351 unlock_page(page); 2404 migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
2352 migrate->cpages--; 2405 migrate->cpages--;
2406 restore++;
2353 2407
2354 putback_lru_page(page); 2408 get_page(page);
2409 putback_lru_page(page);
2410 } else {
2411 migrate->src[i] = 0;
2412 unlock_page(page);
2413 migrate->cpages--;
2414
2415 putback_lru_page(page);
2416 }
2355 } 2417 }
2356 } 2418 }
2419
2420 for (i = 0, addr = start; i < npages && restore; i++, addr += PAGE_SIZE) {
2421 struct page *page = migrate_pfn_to_page(migrate->src[i]);
2422
2423 if (!page || (migrate->src[i] & MIGRATE_PFN_MIGRATE))
2424 continue;
2425
2426 remove_migration_pte(page, migrate->vma, addr, page);
2427
2428 migrate->src[i] = 0;
2429 unlock_page(page);
2430 put_page(page);
2431 restore--;
2432 }
2357} 2433}
2358 2434
2359/* 2435/*
@@ -2380,12 +2456,19 @@ static void migrate_vma_unmap(struct migrate_vma *migrate)
2380 if (!page || !(migrate->src[i] & MIGRATE_PFN_MIGRATE)) 2456 if (!page || !(migrate->src[i] & MIGRATE_PFN_MIGRATE))
2381 continue; 2457 continue;
2382 2458
2383 try_to_unmap(page, flags); 2459 if (page_mapped(page)) {
2384 if (page_mapped(page) || !migrate_vma_check_page(page)) { 2460 try_to_unmap(page, flags);
2385 migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 2461 if (page_mapped(page))
2386 migrate->cpages--; 2462 goto restore;
2387 restore++;
2388 } 2463 }
2464
2465 if (migrate_vma_check_page(page))
2466 continue;
2467
2468restore:
2469 migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
2470 migrate->cpages--;
2471 restore++;
2389 } 2472 }
2390 2473
2391 for (addr = start, i = 0; i < npages && restore; addr += PAGE_SIZE, i++) { 2474 for (addr = start, i = 0; i < npages && restore; addr += PAGE_SIZE, i++) {