aboutsummaryrefslogtreecommitdiffstats
path: root/mm/migrate.c
diff options
context:
space:
mode:
authorLee Schermerhorn <Lee.Schermerhorn@hp.com>2008-10-18 23:26:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-20 11:50:26 -0400
commit894bc310419ac95f4fa4142dc364401a7e607f65 (patch)
tree15d56a7333b41620016b845d2323dd06e822b621 /mm/migrate.c
parent8a7a8544a4f6554ec2d8048ac9f9672f442db5a2 (diff)
Unevictable LRU Infrastructure
When the system contains lots of mlocked or otherwise unevictable pages, the pageout code (kswapd) can spend lots of time scanning over these pages. Worse still, the presence of lots of unevictable pages can confuse kswapd into thinking that more aggressive pageout modes are required, resulting in all kinds of bad behaviour. Infrastructure to manage pages excluded from reclaim--i.e., hidden from vmscan. Based on a patch by Larry Woodman of Red Hat. Reworked to maintain "unevictable" pages on a separate per-zone LRU list, to "hide" them from vmscan. Kosaki Motohiro added the support for the memory controller unevictable lru list. Pages on the unevictable list have both PG_unevictable and PG_lru set. Thus, PG_unevictable is analogous to and mutually exclusive with PG_active--it specifies which LRU list the page is on. The unevictable infrastructure is enabled by a new mm Kconfig option [CONFIG_]UNEVICTABLE_LRU. A new function 'page_evictable(page, vma)' in vmscan.c tests whether or not a page may be evictable. Subsequent patches will add the various !evictable tests. We'll want to keep these tests light-weight for use in shrink_active_list() and, possibly, the fault path. To avoid races between tasks putting pages [back] onto an LRU list and tasks that might be moving the page from non-evictable to evictable state, the new function 'putback_lru_page()' -- inverse to 'isolate_lru_page()' -- tests the "evictability" of a page after placing it on the LRU, before dropping the reference. If the page has become unevictable, putback_lru_page() will redo the 'putback', thus moving the page to the unevictable list. This way, we avoid "stranding" evictable pages on the unevictable list. [akpm@linux-foundation.org: fix fallout from out-of-order merge] [riel@redhat.com: fix UNEVICTABLE_LRU and !PROC_PAGE_MONITOR build] [nishimura@mxp.nes.nec.co.jp: remove redundant mapping check] [kosaki.motohiro@jp.fujitsu.com: unevictable-lru-infrastructure: putback_lru_page()/unevictable page handling rework] [kosaki.motohiro@jp.fujitsu.com: kill unnecessary lock_page() in vmscan.c] [kosaki.motohiro@jp.fujitsu.com: revert migration change of unevictable lru infrastructure] [kosaki.motohiro@jp.fujitsu.com: revert to unevictable-lru-infrastructure-kconfig-fix.patch] [kosaki.motohiro@jp.fujitsu.com: restore patch failure of vmstat-unevictable-and-mlocked-pages-vm-events.patch] Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Signed-off-by: Rik van Riel <riel@redhat.com> Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Debugged-by: Benjamin Kidwell <benjkidwell@yahoo.com> Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/migrate.c')
-rw-r--r--mm/migrate.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/mm/migrate.c b/mm/migrate.c
index c07327487111..b10237d8b459 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -53,14 +53,9 @@ int migrate_prep(void)
53 return 0; 53 return 0;
54} 54}
55 55
56static inline void move_to_lru(struct page *page)
57{
58 lru_cache_add_lru(page, page_lru(page));
59 put_page(page);
60}
61
62/* 56/*
63 * Add isolated pages on the list back to the LRU. 57 * Add isolated pages on the list back to the LRU under page lock
58 * to avoid leaking evictable pages back onto unevictable list.
64 * 59 *
65 * returns the number of pages put back. 60 * returns the number of pages put back.
66 */ 61 */
@@ -72,7 +67,7 @@ int putback_lru_pages(struct list_head *l)
72 67
73 list_for_each_entry_safe(page, page2, l, lru) { 68 list_for_each_entry_safe(page, page2, l, lru) {
74 list_del(&page->lru); 69 list_del(&page->lru);
75 move_to_lru(page); 70 putback_lru_page(page);
76 count++; 71 count++;
77 } 72 }
78 return count; 73 return count;
@@ -354,8 +349,11 @@ static void migrate_page_copy(struct page *newpage, struct page *page)
354 SetPageReferenced(newpage); 349 SetPageReferenced(newpage);
355 if (PageUptodate(page)) 350 if (PageUptodate(page))
356 SetPageUptodate(newpage); 351 SetPageUptodate(newpage);
357 if (PageActive(page)) 352 if (TestClearPageActive(page)) {
353 VM_BUG_ON(PageUnevictable(page));
358 SetPageActive(newpage); 354 SetPageActive(newpage);
355 } else
356 unevictable_migrate_page(newpage, page);
359 if (PageChecked(page)) 357 if (PageChecked(page))
360 SetPageChecked(newpage); 358 SetPageChecked(newpage);
361 if (PageMappedToDisk(page)) 359 if (PageMappedToDisk(page))
@@ -376,7 +374,6 @@ static void migrate_page_copy(struct page *newpage, struct page *page)
376#ifdef CONFIG_SWAP 374#ifdef CONFIG_SWAP
377 ClearPageSwapCache(page); 375 ClearPageSwapCache(page);
378#endif 376#endif
379 ClearPageActive(page);
380 ClearPagePrivate(page); 377 ClearPagePrivate(page);
381 set_page_private(page, 0); 378 set_page_private(page, 0);
382 page->mapping = NULL; 379 page->mapping = NULL;
@@ -555,6 +552,10 @@ static int fallback_migrate_page(struct address_space *mapping,
555 * 552 *
556 * The new page will have replaced the old page if this function 553 * The new page will have replaced the old page if this function
557 * is successful. 554 * is successful.
555 *
556 * Return value:
557 * < 0 - error code
558 * == 0 - success
558 */ 559 */
559static int move_to_new_page(struct page *newpage, struct page *page) 560static int move_to_new_page(struct page *newpage, struct page *page)
560{ 561{
@@ -617,9 +618,10 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
617 if (!newpage) 618 if (!newpage)
618 return -ENOMEM; 619 return -ENOMEM;
619 620
620 if (page_count(page) == 1) 621 if (page_count(page) == 1) {
621 /* page was freed from under us. So we are done. */ 622 /* page was freed from under us. So we are done. */
622 goto move_newpage; 623 goto move_newpage;
624 }
623 625
624 charge = mem_cgroup_prepare_migration(page, newpage); 626 charge = mem_cgroup_prepare_migration(page, newpage);
625 if (charge == -ENOMEM) { 627 if (charge == -ENOMEM) {
@@ -693,7 +695,6 @@ rcu_unlock:
693 rcu_read_unlock(); 695 rcu_read_unlock();
694 696
695unlock: 697unlock:
696
697 unlock_page(page); 698 unlock_page(page);
698 699
699 if (rc != -EAGAIN) { 700 if (rc != -EAGAIN) {
@@ -704,17 +705,19 @@ unlock:
704 * restored. 705 * restored.
705 */ 706 */
706 list_del(&page->lru); 707 list_del(&page->lru);
707 move_to_lru(page); 708 putback_lru_page(page);
708 } 709 }
709 710
710move_newpage: 711move_newpage:
711 if (!charge) 712 if (!charge)
712 mem_cgroup_end_migration(newpage); 713 mem_cgroup_end_migration(newpage);
714
713 /* 715 /*
714 * Move the new page to the LRU. If migration was not successful 716 * Move the new page to the LRU. If migration was not successful
715 * then this will free the page. 717 * then this will free the page.
716 */ 718 */
717 move_to_lru(newpage); 719 putback_lru_page(newpage);
720
718 if (result) { 721 if (result) {
719 if (rc) 722 if (rc)
720 *result = rc; 723 *result = rc;