From: Rik van Riel Simplify the use-once code. I have not benchmarked this change yet, but I expect it to have little impact on most workloads. It gets rid of some magic code though, which is nice. Signed-off-by: Rik van Riel Signed-off-by: Peter Zijlstra include/linux/page-flags.h | 6 ++++++ include/linux/swap.h | 1 - mm/filemap.c | 11 ++--------- mm/page_alloc.c | 3 ++- mm/shmem.c | 7 ++----- mm/swap.c | 28 ++-------------------------- mm/swapfile.c | 4 ++-- mm/vmscan.c | 36 ++++++++++-------------------------- 8 files changed, 26 insertions(+), 70 deletions(-) Index: linux-2.6-uml/include/linux/page-flags.h =================================================================== --- linux-2.6-uml.orig/include/linux/page-flags.h 2006-02-12 16:17:57.000000000 +0100 +++ linux-2.6-uml/include/linux/page-flags.h 2006-02-13 20:18:45.000000000 +0100 @@ -76,6 +76,7 @@ #define PG_nosave_free 18 /* Free, should not be written */ #define PG_uncached 19 /* Page has been mapped as uncached */ +#define PG_new 20 /* Newly allocated page */ /* * Global page accounting. One instance per CPU. Only unsigned longs are * allowed. @@ -344,6 +345,11 @@ extern void __mod_page_state_offset(unsi #define SetPageUncached(page) set_bit(PG_uncached, &(page)->flags) #define ClearPageUncached(page) clear_bit(PG_uncached, &(page)->flags) +#define PageNew(page) test_bit(PG_new, &(page)->flags) +#define SetPageNew(page) set_bit(PG_new, &(page)->flags) +#define ClearPageNew(page) clear_bit(PG_new, &(page)->flags) +#define TestClearPageNew(page) test_and_clear_bit(PG_new, &(page)->flags) + struct page; /* forward declaration */ int test_clear_page_dirty(struct page *page); Index: linux-2.6-uml/mm/filemap.c =================================================================== --- linux-2.6-uml.orig/mm/filemap.c 2006-02-12 16:17:57.000000000 +0100 +++ linux-2.6-uml/mm/filemap.c 2006-02-13 20:18:45.000000000 +0100 @@ -403,6 +403,7 @@ int add_to_page_cache(struct page *page, if (!error) { page_cache_get(page); SetPageLocked(page); + SetPageNew(page); page->mapping = mapping; page->index = offset; mapping->nrpages++; @@ -743,7 +744,6 @@ void do_generic_mapping_read(struct addr unsigned long offset; unsigned long last_index; unsigned long next_index; - unsigned long prev_index; loff_t isize; struct page *cached_page; int error; @@ -752,7 +752,6 @@ void do_generic_mapping_read(struct addr cached_page = NULL; index = *ppos >> PAGE_CACHE_SHIFT; next_index = index; - prev_index = ra.prev_page; last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT; offset = *ppos & ~PAGE_CACHE_MASK; @@ -799,13 +798,7 @@ page_ok: if (mapping_writably_mapped(mapping)) flush_dcache_page(page); - /* - * When (part of) the same page is read multiple times - * in succession, only mark it as accessed the first time. - */ - if (prev_index != index) - mark_page_accessed(page); - prev_index = index; + mark_page_accessed(page); /* * Ok, we have the page, and it's up-to-date, so Index: linux-2.6-uml/mm/shmem.c =================================================================== --- linux-2.6-uml.orig/mm/shmem.c 2006-02-12 16:17:57.000000000 +0100 +++ linux-2.6-uml/mm/shmem.c 2006-02-13 20:18:45.000000000 +0100 @@ -1524,11 +1524,8 @@ static void do_shmem_file_read(struct fi */ if (mapping_writably_mapped(mapping)) flush_dcache_page(page); - /* - * Mark the page accessed if we read the beginning. - */ - if (!offset) - mark_page_accessed(page); + + mark_page_accessed(page); } else { page = ZERO_PAGE(0); page_cache_get(page); Index: linux-2.6-uml/mm/swap.c =================================================================== --- linux-2.6-uml.orig/mm/swap.c 2006-02-12 19:46:19.000000000 +0100 +++ linux-2.6-uml/mm/swap.c 2006-02-13 20:18:45.000000000 +0100 @@ -97,37 +97,12 @@ int rotate_reclaimable_page(struct page } /* - * FIXME: speed this up? - */ -void fastcall activate_page(struct page *page) -{ - struct zone *zone = page_zone(page); - - spin_lock_irq(&zone->lru_lock); - if (PageLRU(page) && !PageActive(page)) { - del_page_from_inactive_list(zone, page); - SetPageActive(page); - add_page_to_active_list(zone, page); - inc_page_state(pgactivate); - } - spin_unlock_irq(&zone->lru_lock); -} - -/* * Mark a page as having seen activity. - * - * inactive,unreferenced -> inactive,referenced - * inactive,referenced -> active,unreferenced - * active,unreferenced -> active,referenced */ void fastcall mark_page_accessed(struct page *page) { - if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) { - activate_page(page); - ClearPageReferenced(page); - } else if (!PageReferenced(page)) { + if (!PageReferenced(page)) SetPageReferenced(page); - } } EXPORT_SYMBOL(mark_page_accessed); @@ -157,6 +132,7 @@ void fastcall lru_cache_add_active(struc if (!pagevec_add(pvec, page)) __pagevec_lru_add_active(pvec); put_cpu_var(lru_add_active_pvecs); + ClearPageNew(page); } static void __lru_add_drain(int cpu) Index: linux-2.6-uml/mm/vmscan.c =================================================================== --- linux-2.6-uml.orig/mm/vmscan.c 2006-02-12 19:46:19.000000000 +0100 +++ linux-2.6-uml/mm/vmscan.c 2006-02-13 20:20:37.000000000 +0100 @@ -243,27 +243,6 @@ int shrink_slab(unsigned long scanned, g return ret; } -/* Called without lock on whether page is mapped, so answer is unstable */ -static inline int page_mapping_inuse(struct page *page) -{ - struct address_space *mapping; - - /* Page is in somebody's page tables. */ - if (page_mapped(page)) - return 1; - - /* Be more reluctant to reclaim swapcache than pagecache */ - if (PageSwapCache(page)) - return 1; - - mapping = page_mapping(page); - if (!mapping) - return 0; - - /* File is mmap'd by somebody? */ - return mapping_mapped(mapping); -} - static inline int is_page_cache_freeable(struct page *page) { return page_count(page) - !!PagePrivate(page) == 2; @@ -455,9 +434,13 @@ static int shrink_list(struct list_head goto keep_locked; referenced = page_referenced(page, 1); - /* In active use or really unfreeable? Activate it. */ - if (referenced && page_mapping_inuse(page)) + + if (referenced) { + /* New page. Wait and see if it gets used again... */ + if (TestClearPageNew(page)) + goto keep_locked; goto activate_locked; + } #ifdef CONFIG_SWAP /* @@ -1195,6 +1178,7 @@ refill_inactive_zone(struct zone *zone, struct page *page; struct pagevec pvec; int reclaim_mapped = 0; + int referenced; if (unlikely(sc->may_swap)) { long mapped_ratio; @@ -1249,10 +1233,10 @@ refill_inactive_zone(struct zone *zone, cond_resched(); page = lru_to_page(&l_hold); list_del(&page->lru); + referenced = page_referenced(page, 0); if (page_mapped(page)) { - if (!reclaim_mapped || - (total_swap_pages == 0 && PageAnon(page)) || - page_referenced(page, 0)) { + if (referenced || !reclaim_mapped || + (total_swap_pages == 0 && PageAnon(page))) { list_add(&page->lru, &l_active); continue; } Index: linux-2.6-uml/mm/swapfile.c =================================================================== --- linux-2.6-uml.orig/mm/swapfile.c 2006-02-12 16:17:57.000000000 +0100 +++ linux-2.6-uml/mm/swapfile.c 2006-02-13 20:18:45.000000000 +0100 @@ -435,7 +435,7 @@ static void unuse_pte(struct vm_area_str * Move the page to the active list so it is not * immediately swapped out again after swapon. */ - activate_page(page); + mark_page_accessed(page); } static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd, @@ -537,7 +537,7 @@ static int unuse_mm(struct mm_struct *mm * Activate page so shrink_cache is unlikely to unmap its * ptes while lock is dropped, so swapoff can make progress. */ - activate_page(page); + mark_page_accessed(page); unlock_page(page); down_read(&mm->mmap_sem); lock_page(page); Index: linux-2.6-uml/include/linux/swap.h =================================================================== --- linux-2.6-uml.orig/include/linux/swap.h 2006-02-12 16:17:57.000000000 +0100 +++ linux-2.6-uml/include/linux/swap.h 2006-02-13 20:18:45.000000000 +0100 @@ -164,7 +164,6 @@ extern unsigned int nr_free_pagecache_pa /* linux/mm/swap.c */ extern void FASTCALL(lru_cache_add(struct page *)); extern void FASTCALL(lru_cache_add_active(struct page *)); -extern void FASTCALL(activate_page(struct page *)); extern void FASTCALL(mark_page_accessed(struct page *)); extern void lru_add_drain(void); extern int lru_add_drain_all(void); Index: linux-2.6-uml/mm/page_alloc.c =================================================================== --- linux-2.6-uml.orig/mm/page_alloc.c 2006-02-12 19:46:19.000000000 +0100 +++ linux-2.6-uml/mm/page_alloc.c 2006-02-13 20:18:45.000000000 +0100 @@ -530,7 +530,8 @@ static int prep_new_page(struct page *pa page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_referenced | 1 << PG_arch_1 | - 1 << PG_checked | 1 << PG_mappedtodisk); + 1 << PG_checked | 1 << PG_mappedtodisk | + 1 << PG_new); set_page_private(page, 0); set_page_refs(page, order); kernel_map_pages(page, 1 << order, 1);