diff options
Diffstat (limited to 'mm/vmscan.c')
-rw-r--r-- | mm/vmscan.c | 56 |
1 files changed, 34 insertions, 22 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 5eecb514ccea..bf903b2d198f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -606,10 +606,6 @@ int putback_lru_pages(struct list_head *l) | |||
606 | /* | 606 | /* |
607 | * swapout a single page | 607 | * swapout a single page |
608 | * page is locked upon entry, unlocked on exit | 608 | * page is locked upon entry, unlocked on exit |
609 | * | ||
610 | * return codes: | ||
611 | * 0 = complete | ||
612 | * 1 = retry | ||
613 | */ | 609 | */ |
614 | static int swap_page(struct page *page) | 610 | static int swap_page(struct page *page) |
615 | { | 611 | { |
@@ -650,7 +646,7 @@ unlock_retry: | |||
650 | unlock_page(page); | 646 | unlock_page(page); |
651 | 647 | ||
652 | retry: | 648 | retry: |
653 | return 1; | 649 | return -EAGAIN; |
654 | } | 650 | } |
655 | /* | 651 | /* |
656 | * migrate_pages | 652 | * migrate_pages |
@@ -669,6 +665,8 @@ retry: | |||
669 | * is only swapping out pages and never touches the second | 665 | * is only swapping out pages and never touches the second |
670 | * list. The direct migration patchset | 666 | * list. The direct migration patchset |
671 | * extends this function to avoid the use of swap. | 667 | * extends this function to avoid the use of swap. |
668 | * | ||
669 | * Return: Number of pages not migrated when "to" ran empty. | ||
672 | */ | 670 | */ |
673 | int migrate_pages(struct list_head *from, struct list_head *to, | 671 | int migrate_pages(struct list_head *from, struct list_head *to, |
674 | struct list_head *moved, struct list_head *failed) | 672 | struct list_head *moved, struct list_head *failed) |
@@ -679,6 +677,7 @@ int migrate_pages(struct list_head *from, struct list_head *to, | |||
679 | struct page *page; | 677 | struct page *page; |
680 | struct page *page2; | 678 | struct page *page2; |
681 | int swapwrite = current->flags & PF_SWAPWRITE; | 679 | int swapwrite = current->flags & PF_SWAPWRITE; |
680 | int rc; | ||
682 | 681 | ||
683 | if (!swapwrite) | 682 | if (!swapwrite) |
684 | current->flags |= PF_SWAPWRITE; | 683 | current->flags |= PF_SWAPWRITE; |
@@ -689,22 +688,23 @@ redo: | |||
689 | list_for_each_entry_safe(page, page2, from, lru) { | 688 | list_for_each_entry_safe(page, page2, from, lru) { |
690 | cond_resched(); | 689 | cond_resched(); |
691 | 690 | ||
692 | if (page_count(page) == 1) { | 691 | rc = 0; |
692 | if (page_count(page) == 1) | ||
693 | /* page was freed from under us. So we are done. */ | 693 | /* page was freed from under us. So we are done. */ |
694 | list_move(&page->lru, moved); | 694 | goto next; |
695 | continue; | 695 | |
696 | } | ||
697 | /* | 696 | /* |
698 | * Skip locked pages during the first two passes to give the | 697 | * Skip locked pages during the first two passes to give the |
699 | * functions holding the lock time to release the page. Later we | 698 | * functions holding the lock time to release the page. Later we |
700 | * use lock_page() to have a higher chance of acquiring the | 699 | * use lock_page() to have a higher chance of acquiring the |
701 | * lock. | 700 | * lock. |
702 | */ | 701 | */ |
702 | rc = -EAGAIN; | ||
703 | if (pass > 2) | 703 | if (pass > 2) |
704 | lock_page(page); | 704 | lock_page(page); |
705 | else | 705 | else |
706 | if (TestSetPageLocked(page)) | 706 | if (TestSetPageLocked(page)) |
707 | goto retry_later; | 707 | goto next; |
708 | 708 | ||
709 | /* | 709 | /* |
710 | * Only wait on writeback if we have already done a pass where | 710 | * Only wait on writeback if we have already done a pass where |
@@ -713,18 +713,19 @@ redo: | |||
713 | if (pass > 0) { | 713 | if (pass > 0) { |
714 | wait_on_page_writeback(page); | 714 | wait_on_page_writeback(page); |
715 | } else { | 715 | } else { |
716 | if (PageWriteback(page)) { | 716 | if (PageWriteback(page)) |
717 | unlock_page(page); | 717 | goto unlock_page; |
718 | goto retry_later; | ||
719 | } | ||
720 | } | 718 | } |
721 | 719 | ||
720 | /* | ||
721 | * Anonymous pages must have swap cache references otherwise | ||
722 | * the information contained in the page maps cannot be | ||
723 | * preserved. | ||
724 | */ | ||
722 | if (PageAnon(page) && !PageSwapCache(page)) { | 725 | if (PageAnon(page) && !PageSwapCache(page)) { |
723 | if (!add_to_swap(page, GFP_KERNEL)) { | 726 | if (!add_to_swap(page, GFP_KERNEL)) { |
724 | unlock_page(page); | 727 | rc = -ENOMEM; |
725 | list_move(&page->lru, failed); | 728 | goto unlock_page; |
726 | nr_failed++; | ||
727 | continue; | ||
728 | } | 729 | } |
729 | } | 730 | } |
730 | 731 | ||
@@ -732,12 +733,23 @@ redo: | |||
732 | * Page is properly locked and writeback is complete. | 733 | * Page is properly locked and writeback is complete. |
733 | * Try to migrate the page. | 734 | * Try to migrate the page. |
734 | */ | 735 | */ |
735 | if (!swap_page(page)) { | 736 | rc = swap_page(page); |
737 | goto next; | ||
738 | |||
739 | unlock_page: | ||
740 | unlock_page(page); | ||
741 | |||
742 | next: | ||
743 | if (rc == -EAGAIN) { | ||
744 | retry++; | ||
745 | } else if (rc) { | ||
746 | /* Permanent failure */ | ||
747 | list_move(&page->lru, failed); | ||
748 | nr_failed++; | ||
749 | } else { | ||
750 | /* Success */ | ||
736 | list_move(&page->lru, moved); | 751 | list_move(&page->lru, moved); |
737 | continue; | ||
738 | } | 752 | } |
739 | retry_later: | ||
740 | retry++; | ||
741 | } | 753 | } |
742 | if (retry && pass++ < 10) | 754 | if (retry && pass++ < 10) |
743 | goto redo; | 755 | goto redo; |