diff options
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 58 |
1 files changed, 38 insertions, 20 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 352de555626c..34132f8e9109 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -375,7 +375,7 @@ void migrate_page_copy(struct page *newpage, struct page *page) | |||
375 | * redo the accounting that clear_page_dirty_for_io undid, | 375 | * redo the accounting that clear_page_dirty_for_io undid, |
376 | * but we can't use set_page_dirty because that function | 376 | * but we can't use set_page_dirty because that function |
377 | * is actually a signal that all of the page has become dirty. | 377 | * is actually a signal that all of the page has become dirty. |
378 | * Wheras only part of our page may be dirty. | 378 | * Whereas only part of our page may be dirty. |
379 | */ | 379 | */ |
380 | __set_page_dirty_nobuffers(newpage); | 380 | __set_page_dirty_nobuffers(newpage); |
381 | } | 381 | } |
@@ -564,7 +564,7 @@ static int fallback_migrate_page(struct address_space *mapping, | |||
564 | * == 0 - success | 564 | * == 0 - success |
565 | */ | 565 | */ |
566 | static int move_to_new_page(struct page *newpage, struct page *page, | 566 | static int move_to_new_page(struct page *newpage, struct page *page, |
567 | int remap_swapcache) | 567 | int remap_swapcache, bool sync) |
568 | { | 568 | { |
569 | struct address_space *mapping; | 569 | struct address_space *mapping; |
570 | int rc; | 570 | int rc; |
@@ -586,18 +586,28 @@ static int move_to_new_page(struct page *newpage, struct page *page, | |||
586 | mapping = page_mapping(page); | 586 | mapping = page_mapping(page); |
587 | if (!mapping) | 587 | if (!mapping) |
588 | rc = migrate_page(mapping, newpage, page); | 588 | rc = migrate_page(mapping, newpage, page); |
589 | else if (mapping->a_ops->migratepage) | 589 | else { |
590 | /* | 590 | /* |
591 | * Most pages have a mapping and most filesystems | 591 | * Do not writeback pages if !sync and migratepage is |
592 | * should provide a migration function. Anonymous | 592 | * not pointing to migrate_page() which is nonblocking |
593 | * pages are part of swap space which also has its | 593 | * (swapcache/tmpfs uses migratepage = migrate_page). |
594 | * own migration function. This is the most common | ||
595 | * path for page migration. | ||
596 | */ | 594 | */ |
597 | rc = mapping->a_ops->migratepage(mapping, | 595 | if (PageDirty(page) && !sync && |
598 | newpage, page); | 596 | mapping->a_ops->migratepage != migrate_page) |
599 | else | 597 | rc = -EBUSY; |
600 | rc = fallback_migrate_page(mapping, newpage, page); | 598 | else if (mapping->a_ops->migratepage) |
599 | /* | ||
600 | * Most pages have a mapping and most filesystems | ||
601 | * should provide a migration function. Anonymous | ||
602 | * pages are part of swap space which also has its | ||
603 | * own migration function. This is the most common | ||
604 | * path for page migration. | ||
605 | */ | ||
606 | rc = mapping->a_ops->migratepage(mapping, | ||
607 | newpage, page); | ||
608 | else | ||
609 | rc = fallback_migrate_page(mapping, newpage, page); | ||
610 | } | ||
601 | 611 | ||
602 | if (rc) { | 612 | if (rc) { |
603 | newpage->mapping = NULL; | 613 | newpage->mapping = NULL; |
@@ -623,7 +633,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
623 | struct page *newpage = get_new_page(page, private, &result); | 633 | struct page *newpage = get_new_page(page, private, &result); |
624 | int remap_swapcache = 1; | 634 | int remap_swapcache = 1; |
625 | int charge = 0; | 635 | int charge = 0; |
626 | struct mem_cgroup *mem = NULL; | 636 | struct mem_cgroup *mem; |
627 | struct anon_vma *anon_vma = NULL; | 637 | struct anon_vma *anon_vma = NULL; |
628 | 638 | ||
629 | if (!newpage) | 639 | if (!newpage) |
@@ -641,7 +651,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
641 | rc = -EAGAIN; | 651 | rc = -EAGAIN; |
642 | 652 | ||
643 | if (!trylock_page(page)) { | 653 | if (!trylock_page(page)) { |
644 | if (!force) | 654 | if (!force || !sync) |
645 | goto move_newpage; | 655 | goto move_newpage; |
646 | 656 | ||
647 | /* | 657 | /* |
@@ -678,7 +688,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
678 | } | 688 | } |
679 | 689 | ||
680 | /* charge against new page */ | 690 | /* charge against new page */ |
681 | charge = mem_cgroup_prepare_migration(page, newpage, &mem); | 691 | charge = mem_cgroup_prepare_migration(page, newpage, &mem, GFP_KERNEL); |
682 | if (charge == -ENOMEM) { | 692 | if (charge == -ENOMEM) { |
683 | rc = -ENOMEM; | 693 | rc = -ENOMEM; |
684 | goto unlock; | 694 | goto unlock; |
@@ -686,7 +696,15 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
686 | BUG_ON(charge); | 696 | BUG_ON(charge); |
687 | 697 | ||
688 | if (PageWriteback(page)) { | 698 | if (PageWriteback(page)) { |
689 | if (!force || !sync) | 699 | /* |
700 | * For !sync, there is no point retrying as the retry loop | ||
701 | * is expected to be too short for PageWriteback to be cleared | ||
702 | */ | ||
703 | if (!sync) { | ||
704 | rc = -EBUSY; | ||
705 | goto uncharge; | ||
706 | } | ||
707 | if (!force) | ||
690 | goto uncharge; | 708 | goto uncharge; |
691 | wait_on_page_writeback(page); | 709 | wait_on_page_writeback(page); |
692 | } | 710 | } |
@@ -757,14 +775,14 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
757 | 775 | ||
758 | skip_unmap: | 776 | skip_unmap: |
759 | if (!page_mapped(page)) | 777 | if (!page_mapped(page)) |
760 | rc = move_to_new_page(newpage, page, remap_swapcache); | 778 | rc = move_to_new_page(newpage, page, remap_swapcache, sync); |
761 | 779 | ||
762 | if (rc && remap_swapcache) | 780 | if (rc && remap_swapcache) |
763 | remove_migration_ptes(page, page); | 781 | remove_migration_ptes(page, page); |
764 | 782 | ||
765 | /* Drop an anon_vma reference if we took one */ | 783 | /* Drop an anon_vma reference if we took one */ |
766 | if (anon_vma) | 784 | if (anon_vma) |
767 | drop_anon_vma(anon_vma); | 785 | put_anon_vma(anon_vma); |
768 | 786 | ||
769 | uncharge: | 787 | uncharge: |
770 | if (!charge) | 788 | if (!charge) |
@@ -850,13 +868,13 @@ static int unmap_and_move_huge_page(new_page_t get_new_page, | |||
850 | try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS); | 868 | try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS); |
851 | 869 | ||
852 | if (!page_mapped(hpage)) | 870 | if (!page_mapped(hpage)) |
853 | rc = move_to_new_page(new_hpage, hpage, 1); | 871 | rc = move_to_new_page(new_hpage, hpage, 1, sync); |
854 | 872 | ||
855 | if (rc) | 873 | if (rc) |
856 | remove_migration_ptes(hpage, hpage); | 874 | remove_migration_ptes(hpage, hpage); |
857 | 875 | ||
858 | if (anon_vma) | 876 | if (anon_vma) |
859 | drop_anon_vma(anon_vma); | 877 | put_anon_vma(anon_vma); |
860 | out: | 878 | out: |
861 | unlock_page(hpage); | 879 | unlock_page(hpage); |
862 | 880 | ||