diff options
-rw-r--r-- | mm/vmscan.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 12b692164bcc..512f4630ba8c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -622,6 +622,24 @@ static enum page_references page_check_references(struct page *page, | |||
622 | return PAGEREF_RECLAIM; | 622 | return PAGEREF_RECLAIM; |
623 | } | 623 | } |
624 | 624 | ||
625 | static noinline_for_stack void free_page_list(struct list_head *free_pages) | ||
626 | { | ||
627 | struct pagevec freed_pvec; | ||
628 | struct page *page, *tmp; | ||
629 | |||
630 | pagevec_init(&freed_pvec, 1); | ||
631 | |||
632 | list_for_each_entry_safe(page, tmp, free_pages, lru) { | ||
633 | list_del(&page->lru); | ||
634 | if (!pagevec_add(&freed_pvec, page)) { | ||
635 | __pagevec_free(&freed_pvec); | ||
636 | pagevec_reinit(&freed_pvec); | ||
637 | } | ||
638 | } | ||
639 | |||
640 | pagevec_free(&freed_pvec); | ||
641 | } | ||
642 | |||
625 | /* | 643 | /* |
626 | * shrink_page_list() returns the number of reclaimed pages | 644 | * shrink_page_list() returns the number of reclaimed pages |
627 | */ | 645 | */ |
@@ -630,13 +648,12 @@ static unsigned long shrink_page_list(struct list_head *page_list, | |||
630 | enum pageout_io sync_writeback) | 648 | enum pageout_io sync_writeback) |
631 | { | 649 | { |
632 | LIST_HEAD(ret_pages); | 650 | LIST_HEAD(ret_pages); |
633 | struct pagevec freed_pvec; | 651 | LIST_HEAD(free_pages); |
634 | int pgactivate = 0; | 652 | int pgactivate = 0; |
635 | unsigned long nr_reclaimed = 0; | 653 | unsigned long nr_reclaimed = 0; |
636 | 654 | ||
637 | cond_resched(); | 655 | cond_resched(); |
638 | 656 | ||
639 | pagevec_init(&freed_pvec, 1); | ||
640 | while (!list_empty(page_list)) { | 657 | while (!list_empty(page_list)) { |
641 | enum page_references references; | 658 | enum page_references references; |
642 | struct address_space *mapping; | 659 | struct address_space *mapping; |
@@ -811,10 +828,12 @@ static unsigned long shrink_page_list(struct list_head *page_list, | |||
811 | __clear_page_locked(page); | 828 | __clear_page_locked(page); |
812 | free_it: | 829 | free_it: |
813 | nr_reclaimed++; | 830 | nr_reclaimed++; |
814 | if (!pagevec_add(&freed_pvec, page)) { | 831 | |
815 | __pagevec_free(&freed_pvec); | 832 | /* |
816 | pagevec_reinit(&freed_pvec); | 833 | * Is there need to periodically free_page_list? It would |
817 | } | 834 | * appear not as the counts should be low |
835 | */ | ||
836 | list_add(&page->lru, &free_pages); | ||
818 | continue; | 837 | continue; |
819 | 838 | ||
820 | cull_mlocked: | 839 | cull_mlocked: |
@@ -837,9 +856,10 @@ keep: | |||
837 | list_add(&page->lru, &ret_pages); | 856 | list_add(&page->lru, &ret_pages); |
838 | VM_BUG_ON(PageLRU(page) || PageUnevictable(page)); | 857 | VM_BUG_ON(PageLRU(page) || PageUnevictable(page)); |
839 | } | 858 | } |
859 | |||
860 | free_page_list(&free_pages); | ||
861 | |||
840 | list_splice(&ret_pages, page_list); | 862 | list_splice(&ret_pages, page_list); |
841 | if (pagevec_count(&freed_pvec)) | ||
842 | __pagevec_free(&freed_pvec); | ||
843 | count_vm_events(PGACTIVATE, pgactivate); | 863 | count_vm_events(PGACTIVATE, pgactivate); |
844 | return nr_reclaimed; | 864 | return nr_reclaimed; |
845 | } | 865 | } |