aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2013-07-03 18:02:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:07:31 -0400
commit13f7f78981e49f288d871bb918545ef5c952e00b (patch)
treeacc426750a6dfcfe4a79ba352b4bc10463f7dd39 /mm
parentc6286c983900c77410a951874f1589f4a41fbbae (diff)
mm: pagevec: defer deciding which LRU to add a page to until pagevec drain time
mark_page_accessed() cannot activate an inactive page that is located on an inactive LRU pagevec. Hints from filesystems may be ignored as a result. In preparation for fixing that problem, this patch removes the per-LRU pagevecs and leaves just one pagevec. The final LRU the page is added to is deferred until the pagevec is drained. This means that fewer pagevecs are available and potentially there is greater contention on the LRU lock. However, this only applies in the case where there is an almost perfect mix of file, anon, active and inactive pages being added to the LRU. In practice I expect that we are adding stream of pages of a particular time and that the changes in contention will barely be measurable. Signed-off-by: Mel Gorman <mgorman@suse.de> Acked-by: Rik van Riel <riel@redhat.com> Cc: Jan Kara <jack@suse.cz> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Alexey Lyahkov <alexey.lyashkov@gmail.com> Cc: Andrew Perepechko <anserper@ya.ru> Cc: Robin Dong <sanbai@taobao.com> Cc: Theodore Tso <tytso@mit.edu> Cc: Hugh Dickins <hughd@google.com> Cc: Rik van Riel <riel@redhat.com> Cc: Bernd Schubert <bernd.schubert@fastmail.fm> Cc: David Howells <dhowells@redhat.com> Cc: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/swap.c47
1 files changed, 21 insertions, 26 deletions
diff --git a/mm/swap.c b/mm/swap.c
index 53c9ceb7b816..868b493431c2 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -40,7 +40,7 @@
40/* How many pages do we try to swap or page in/out together? */ 40/* How many pages do we try to swap or page in/out together? */
41int page_cluster; 41int page_cluster;
42 42
43static DEFINE_PER_CPU(struct pagevec[NR_LRU_LISTS], lru_add_pvecs); 43static DEFINE_PER_CPU(struct pagevec, lru_add_pvec);
44static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs); 44static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
45static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs); 45static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs);
46 46
@@ -452,22 +452,25 @@ void mark_page_accessed(struct page *page)
452EXPORT_SYMBOL(mark_page_accessed); 452EXPORT_SYMBOL(mark_page_accessed);
453 453
454/* 454/*
455 * Order of operations is important: flush the pagevec when it's already 455 * Queue the page for addition to the LRU via pagevec. The decision on whether
456 * full, not when adding the last page, to make sure that last page is 456 * to add the page to the [in]active [file|anon] list is deferred until the
457 * not added to the LRU directly when passed to this function. Because 457 * pagevec is drained. This gives a chance for the caller of __lru_cache_add()
458 * mark_page_accessed() (called after this when writing) only activates 458 * have the page added to the active list using mark_page_accessed().
459 * pages that are on the LRU, linear writes in subpage chunks would see
460 * every PAGEVEC_SIZE page activated, which is unexpected.
461 */ 459 */
462void __lru_cache_add(struct page *page, enum lru_list lru) 460void __lru_cache_add(struct page *page, enum lru_list lru)
463{ 461{
464 struct pagevec *pvec = &get_cpu_var(lru_add_pvecs)[lru]; 462 struct pagevec *pvec = &get_cpu_var(lru_add_pvec);
463
464 if (is_active_lru(lru))
465 SetPageActive(page);
466 else
467 ClearPageActive(page);
465 468
466 page_cache_get(page); 469 page_cache_get(page);
467 if (!pagevec_space(pvec)) 470 if (!pagevec_space(pvec))
468 __pagevec_lru_add(pvec, lru); 471 __pagevec_lru_add(pvec, lru);
469 pagevec_add(pvec, page); 472 pagevec_add(pvec, page);
470 put_cpu_var(lru_add_pvecs); 473 put_cpu_var(lru_add_pvec);
471} 474}
472EXPORT_SYMBOL(__lru_cache_add); 475EXPORT_SYMBOL(__lru_cache_add);
473 476
@@ -480,13 +483,11 @@ void lru_cache_add_lru(struct page *page, enum lru_list lru)
480{ 483{
481 if (PageActive(page)) { 484 if (PageActive(page)) {
482 VM_BUG_ON(PageUnevictable(page)); 485 VM_BUG_ON(PageUnevictable(page));
483 ClearPageActive(page);
484 } else if (PageUnevictable(page)) { 486 } else if (PageUnevictable(page)) {
485 VM_BUG_ON(PageActive(page)); 487 VM_BUG_ON(PageActive(page));
486 ClearPageUnevictable(page);
487 } 488 }
488 489
489 VM_BUG_ON(PageLRU(page) || PageActive(page) || PageUnevictable(page)); 490 VM_BUG_ON(PageLRU(page));
490 __lru_cache_add(page, lru); 491 __lru_cache_add(page, lru);
491} 492}
492 493
@@ -587,15 +588,10 @@ static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec,
587 */ 588 */
588void lru_add_drain_cpu(int cpu) 589void lru_add_drain_cpu(int cpu)
589{ 590{
590 struct pagevec *pvecs = per_cpu(lru_add_pvecs, cpu); 591 struct pagevec *pvec = &per_cpu(lru_add_pvec, cpu);
591 struct pagevec *pvec;
592 int lru;
593 592
594 for_each_lru(lru) { 593 if (pagevec_count(pvec))
595 pvec = &pvecs[lru - LRU_BASE]; 594 __pagevec_lru_add(pvec, NR_LRU_LISTS);
596 if (pagevec_count(pvec))
597 __pagevec_lru_add(pvec, lru);
598 }
599 595
600 pvec = &per_cpu(lru_rotate_pvecs, cpu); 596 pvec = &per_cpu(lru_rotate_pvecs, cpu);
601 if (pagevec_count(pvec)) { 597 if (pagevec_count(pvec)) {
@@ -799,17 +795,16 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
799static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, 795static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
800 void *arg) 796 void *arg)
801{ 797{
802 enum lru_list lru = (enum lru_list)arg; 798 enum lru_list requested_lru = (enum lru_list)arg;
803 int file = is_file_lru(lru); 799 int file = page_is_file_cache(page);
804 int active = is_active_lru(lru); 800 int active = PageActive(page);
801 enum lru_list lru = page_lru(page);
805 802
806 VM_BUG_ON(PageActive(page)); 803 WARN_ON_ONCE(requested_lru < NR_LRU_LISTS && requested_lru != lru);
807 VM_BUG_ON(PageUnevictable(page)); 804 VM_BUG_ON(PageUnevictable(page));
808 VM_BUG_ON(PageLRU(page)); 805 VM_BUG_ON(PageLRU(page));
809 806
810 SetPageLRU(page); 807 SetPageLRU(page);
811 if (active)
812 SetPageActive(page);
813 add_page_to_lru_list(page, lruvec, lru); 808 add_page_to_lru_list(page, lruvec, lru);
814 update_page_reclaim_stat(lruvec, file, active); 809 update_page_reclaim_stat(lruvec, file, active);
815 trace_mm_lru_insertion(page, page_to_pfn(page), lru, trace_pagemap_flags(page)); 810 trace_mm_lru_insertion(page, page_to_pfn(page), lru, trace_pagemap_flags(page));