aboutsummaryrefslogtreecommitdiffstats
path: root/mm/vmscan.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2008-10-18 23:26:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-20 11:52:30 -0400
commitb291f000393f5a0b679012b39d79fbc85c018233 (patch)
tree28eb785d4d157d3396e4377294e6054635a4bd90 /mm/vmscan.c
parent89e004ea55abe201b29e2d6e35124101f1288ef7 (diff)
mlock: mlocked pages are unevictable
Make sure that mlocked pages also live on the unevictable LRU, so kswapd will not scan them over and over again. This is achieved through various strategies: 1) add yet another page flag--PG_mlocked--to indicate that the page is locked for efficient testing in vmscan and, optionally, fault path. This allows early culling of unevictable pages, preventing them from getting to page_referenced()/try_to_unmap(). Also allows separate accounting of mlock'd pages, as Nick's original patch did. Note: Nick's original mlock patch used a PG_mlocked flag. I had removed this in favor of the PG_unevictable flag + an mlock_count [new page struct member]. I restored the PG_mlocked flag to eliminate the new count field. 2) add the mlock/unevictable infrastructure to mm/mlock.c, with internal APIs in mm/internal.h. This is a rework of Nick's original patch to these files, taking into account that mlocked pages are now kept on unevictable LRU list. 3) update vmscan.c:page_evictable() to check PageMlocked() and, if vma passed in, the vm_flags. Note that the vma will only be passed in for new pages in the fault path; and then only if the "cull unevictable pages in fault path" patch is included. 4) add try_to_unlock() to rmap.c to walk a page's rmap and ClearPageMlocked() if no other vmas have it mlocked. Reuses as much of try_to_unmap() as possible. This effectively replaces the use of one of the lru list links as an mlock count. If this mechanism let's pages in mlocked vmas leak through w/o PG_mlocked set [I don't know that it does], we should catch them later in try_to_unmap(). One hopes this will be rare, as it will be relatively expensive. Original mm/internal.h, mm/rmap.c and mm/mlock.c changes: Signed-off-by: Nick Piggin <npiggin@suse.de> splitlru: introduce __get_user_pages(): New munlock processing need to GUP_FLAGS_IGNORE_VMA_PERMISSIONS. because current get_user_pages() can't grab PROT_NONE pages theresore it cause PROT_NONE pages can't munlock. [akpm@linux-foundation.org: fix this for pagemap-pass-mm-into-pagewalkers.patch] [akpm@linux-foundation.org: untangle patch interdependencies] [akpm@linux-foundation.org: fix things after out-of-order merging] [hugh@veritas.com: fix page-flags mess] [lee.schermerhorn@hp.com: fix munlock page table walk - now requires 'mm'] [kosaki.motohiro@jp.fujitsu.com: build fix] [kosaki.motohiro@jp.fujitsu.com: fix truncate race and sevaral comments] [kosaki.motohiro@jp.fujitsu.com: splitlru: introduce __get_user_pages()] Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Rik van Riel <riel@redhat.com> Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Cc: Nick Piggin <npiggin@suse.de> Cc: Dave Hansen <dave@linux.vnet.ibm.com> Cc: Matt Mackall <mpm@selenic.com> Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/vmscan.c')
-rw-r--r--mm/vmscan.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c
index dfb342e0db9b..e5aaaad159ef 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -582,11 +582,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
582 582
583 sc->nr_scanned++; 583 sc->nr_scanned++;
584 584
585 if (unlikely(!page_evictable(page, NULL))) { 585 if (unlikely(!page_evictable(page, NULL)))
586 unlock_page(page); 586 goto cull_mlocked;
587 putback_lru_page(page);
588 continue;
589 }
590 587
591 if (!sc->may_swap && page_mapped(page)) 588 if (!sc->may_swap && page_mapped(page))
592 goto keep_locked; 589 goto keep_locked;
@@ -624,9 +621,19 @@ static unsigned long shrink_page_list(struct list_head *page_list,
624 * Anonymous process memory has backing store? 621 * Anonymous process memory has backing store?
625 * Try to allocate it some swap space here. 622 * Try to allocate it some swap space here.
626 */ 623 */
627 if (PageAnon(page) && !PageSwapCache(page)) 624 if (PageAnon(page) && !PageSwapCache(page)) {
625 switch (try_to_munlock(page)) {
626 case SWAP_FAIL: /* shouldn't happen */
627 case SWAP_AGAIN:
628 goto keep_locked;
629 case SWAP_MLOCK:
630 goto cull_mlocked;
631 case SWAP_SUCCESS:
632 ; /* fall thru'; add to swap cache */
633 }
628 if (!add_to_swap(page, GFP_ATOMIC)) 634 if (!add_to_swap(page, GFP_ATOMIC))
629 goto activate_locked; 635 goto activate_locked;
636 }
630#endif /* CONFIG_SWAP */ 637#endif /* CONFIG_SWAP */
631 638
632 mapping = page_mapping(page); 639 mapping = page_mapping(page);
@@ -641,6 +648,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
641 goto activate_locked; 648 goto activate_locked;
642 case SWAP_AGAIN: 649 case SWAP_AGAIN:
643 goto keep_locked; 650 goto keep_locked;
651 case SWAP_MLOCK:
652 goto cull_mlocked;
644 case SWAP_SUCCESS: 653 case SWAP_SUCCESS:
645 ; /* try to free the page below */ 654 ; /* try to free the page below */
646 } 655 }
@@ -731,6 +740,11 @@ free_it:
731 } 740 }
732 continue; 741 continue;
733 742
743cull_mlocked:
744 unlock_page(page);
745 putback_lru_page(page);
746 continue;
747
734activate_locked: 748activate_locked:
735 /* Not a candidate for swapping, so reclaim swap space. */ 749 /* Not a candidate for swapping, so reclaim swap space. */
736 if (PageSwapCache(page) && vm_swap_full()) 750 if (PageSwapCache(page) && vm_swap_full())
@@ -742,7 +756,7 @@ keep_locked:
742 unlock_page(page); 756 unlock_page(page);
743keep: 757keep:
744 list_add(&page->lru, &ret_pages); 758 list_add(&page->lru, &ret_pages);
745 VM_BUG_ON(PageLRU(page)); 759 VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
746 } 760 }
747 list_splice(&ret_pages, page_list); 761 list_splice(&ret_pages, page_list);
748 if (pagevec_count(&freed_pvec)) 762 if (pagevec_count(&freed_pvec))
@@ -2329,12 +2343,13 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
2329 * @vma: the VMA in which the page is or will be mapped, may be NULL 2343 * @vma: the VMA in which the page is or will be mapped, may be NULL
2330 * 2344 *
2331 * Test whether page is evictable--i.e., should be placed on active/inactive 2345 * Test whether page is evictable--i.e., should be placed on active/inactive
2332 * lists vs unevictable list. 2346 * lists vs unevictable list. The vma argument is !NULL when called from the
2347 * fault path to determine how to instantate a new page.
2333 * 2348 *
2334 * Reasons page might not be evictable: 2349 * Reasons page might not be evictable:
2335 * (1) page's mapping marked unevictable 2350 * (1) page's mapping marked unevictable
2351 * (2) page is part of an mlocked VMA
2336 * 2352 *
2337 * TODO - later patches
2338 */ 2353 */
2339int page_evictable(struct page *page, struct vm_area_struct *vma) 2354int page_evictable(struct page *page, struct vm_area_struct *vma)
2340{ 2355{
@@ -2342,7 +2357,8 @@ int page_evictable(struct page *page, struct vm_area_struct *vma)
2342 if (mapping_unevictable(page_mapping(page))) 2357 if (mapping_unevictable(page_mapping(page)))
2343 return 0; 2358 return 0;
2344 2359
2345 /* TODO: test page [!]evictable conditions */ 2360 if (PageMlocked(page) || (vma && is_mlocked_vma(vma, page)))
2361 return 0;
2346 2362
2347 return 1; 2363 return 1;
2348} 2364}