aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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++) {