diff options
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 53 |
1 files changed, 21 insertions, 32 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 81721a061d50..8f91463eab4e 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -254,14 +254,20 @@ static int migrate_page_move_mapping(struct address_space *mapping, | |||
254 | { | 254 | { |
255 | struct page **radix_pointer; | 255 | struct page **radix_pointer; |
256 | 256 | ||
257 | if (!mapping) { | ||
258 | /* Anonymous page */ | ||
259 | if (page_count(page) != 1) | ||
260 | return -EAGAIN; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
257 | write_lock_irq(&mapping->tree_lock); | 264 | write_lock_irq(&mapping->tree_lock); |
258 | 265 | ||
259 | radix_pointer = (struct page **)radix_tree_lookup_slot( | 266 | radix_pointer = (struct page **)radix_tree_lookup_slot( |
260 | &mapping->page_tree, | 267 | &mapping->page_tree, |
261 | page_index(page)); | 268 | page_index(page)); |
262 | 269 | ||
263 | if (!page_mapping(page) || | 270 | if (page_count(page) != 2 + !!PagePrivate(page) || |
264 | page_count(page) != 2 + !!PagePrivate(page) || | ||
265 | *radix_pointer != page) { | 271 | *radix_pointer != page) { |
266 | write_unlock_irq(&mapping->tree_lock); | 272 | write_unlock_irq(&mapping->tree_lock); |
267 | return -EAGAIN; | 273 | return -EAGAIN; |
@@ -271,10 +277,12 @@ static int migrate_page_move_mapping(struct address_space *mapping, | |||
271 | * Now we know that no one else is looking at the page. | 277 | * Now we know that no one else is looking at the page. |
272 | */ | 278 | */ |
273 | get_page(newpage); | 279 | get_page(newpage); |
280 | #ifdef CONFIG_SWAP | ||
274 | if (PageSwapCache(page)) { | 281 | if (PageSwapCache(page)) { |
275 | SetPageSwapCache(newpage); | 282 | SetPageSwapCache(newpage); |
276 | set_page_private(newpage, page_private(page)); | 283 | set_page_private(newpage, page_private(page)); |
277 | } | 284 | } |
285 | #endif | ||
278 | 286 | ||
279 | *radix_pointer = newpage; | 287 | *radix_pointer = newpage; |
280 | __put_page(page); | 288 | __put_page(page); |
@@ -308,7 +316,9 @@ static void migrate_page_copy(struct page *newpage, struct page *page) | |||
308 | set_page_dirty(newpage); | 316 | set_page_dirty(newpage); |
309 | } | 317 | } |
310 | 318 | ||
319 | #ifdef CONFIG_SWAP | ||
311 | ClearPageSwapCache(page); | 320 | ClearPageSwapCache(page); |
321 | #endif | ||
312 | ClearPageActive(page); | 322 | ClearPageActive(page); |
313 | ClearPagePrivate(page); | 323 | ClearPagePrivate(page); |
314 | set_page_private(page, 0); | 324 | set_page_private(page, 0); |
@@ -353,16 +363,6 @@ int migrate_page(struct address_space *mapping, | |||
353 | return rc; | 363 | return rc; |
354 | 364 | ||
355 | migrate_page_copy(newpage, page); | 365 | migrate_page_copy(newpage, page); |
356 | |||
357 | /* | ||
358 | * Remove auxiliary swap entries and replace | ||
359 | * them with real ptes. | ||
360 | * | ||
361 | * Note that a real pte entry will allow processes that are not | ||
362 | * waiting on the page lock to use the new page via the page tables | ||
363 | * before the new page is unlocked. | ||
364 | */ | ||
365 | remove_from_swap(newpage); | ||
366 | return 0; | 366 | return 0; |
367 | } | 367 | } |
368 | EXPORT_SYMBOL(migrate_page); | 368 | EXPORT_SYMBOL(migrate_page); |
@@ -530,23 +530,7 @@ redo: | |||
530 | goto unlock_page; | 530 | goto unlock_page; |
531 | 531 | ||
532 | /* | 532 | /* |
533 | * Establish swap ptes for anonymous pages or destroy pte | 533 | * Establish migration ptes or remove ptes |
534 | * maps for files. | ||
535 | * | ||
536 | * In order to reestablish file backed mappings the fault handlers | ||
537 | * will take the radix tree_lock which may then be used to stop | ||
538 | * processses from accessing this page until the new page is ready. | ||
539 | * | ||
540 | * A process accessing via a swap pte (an anonymous page) will take a | ||
541 | * page_lock on the old page which will block the process until the | ||
542 | * migration attempt is complete. At that time the PageSwapCache bit | ||
543 | * will be examined. If the page was migrated then the PageSwapCache | ||
544 | * bit will be clear and the operation to retrieve the page will be | ||
545 | * retried which will find the new page in the radix tree. Then a new | ||
546 | * direct mapping may be generated based on the radix tree contents. | ||
547 | * | ||
548 | * If the page was not migrated then the PageSwapCache bit | ||
549 | * is still set and the operation may continue. | ||
550 | */ | 534 | */ |
551 | rc = -EPERM; | 535 | rc = -EPERM; |
552 | if (try_to_unmap(page, 1) == SWAP_FAIL) | 536 | if (try_to_unmap(page, 1) == SWAP_FAIL) |
@@ -569,9 +553,9 @@ redo: | |||
569 | */ | 553 | */ |
570 | mapping = page_mapping(page); | 554 | mapping = page_mapping(page); |
571 | if (!mapping) | 555 | if (!mapping) |
572 | goto unlock_both; | 556 | rc = migrate_page(mapping, newpage, page); |
573 | 557 | ||
574 | if (mapping->a_ops->migratepage) | 558 | else if (mapping->a_ops->migratepage) |
575 | /* | 559 | /* |
576 | * Most pages have a mapping and most filesystems | 560 | * Most pages have a mapping and most filesystems |
577 | * should provide a migration function. Anonymous | 561 | * should provide a migration function. Anonymous |
@@ -584,10 +568,15 @@ redo: | |||
584 | else | 568 | else |
585 | rc = fallback_migrate_page(mapping, newpage, page); | 569 | rc = fallback_migrate_page(mapping, newpage, page); |
586 | 570 | ||
587 | unlock_both: | 571 | if (!rc) |
572 | remove_migration_ptes(page, newpage); | ||
573 | |||
588 | unlock_page(newpage); | 574 | unlock_page(newpage); |
589 | 575 | ||
590 | unlock_page: | 576 | unlock_page: |
577 | if (rc) | ||
578 | remove_migration_ptes(page, page); | ||
579 | |||
591 | unlock_page(page); | 580 | unlock_page(page); |
592 | 581 | ||
593 | next: | 582 | next: |