diff -urN vm-ref/arch/sparc/kernel/sys_sunos.c vm/arch/sparc/kernel/sys_sunos.c --- vm-ref/arch/sparc/kernel/sys_sunos.c Tue Jan 22 18:52:53 2002 +++ vm/arch/sparc/kernel/sys_sunos.c Fri Mar 29 18:44:01 2002 @@ -193,7 +193,7 @@ * fool it, but this should catch most mistakes. */ freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; - freepages += atomic_read(&page_cache_size); + freepages += page_cache_size; freepages >>= 1; freepages += nr_free_pages(); freepages += nr_swap_pages; diff -urN vm-ref/arch/sparc64/kernel/sys_sunos32.c vm/arch/sparc64/kernel/sys_sunos32.c --- vm-ref/arch/sparc64/kernel/sys_sunos32.c Tue Jan 22 18:52:53 2002 +++ vm/arch/sparc64/kernel/sys_sunos32.c Fri Mar 29 18:44:01 2002 @@ -157,7 +157,7 @@ * fool it, but this should catch most mistakes. */ freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; - freepages += atomic_read(&page_cache_size); + freepages += page_cache_size; freepages >>= 1; freepages += nr_free_pages(); freepages += nr_swap_pages; diff -urN vm-ref/fs/buffer.c vm/fs/buffer.c --- vm-ref/fs/buffer.c Fri Mar 29 18:39:38 2002 +++ vm/fs/buffer.c Fri Mar 29 18:44:01 2002 @@ -2787,10 +2787,10 @@ #endif printk("Buffer memory: %6dkB\n", - atomic_read(&buffermem_pages) << (PAGE_SHIFT-10)); + atomic_read(&buffermem_pages) << (PAGE_SHIFT-10)); - printk("Cache memory: %6dkB\n", - (atomic_read(&page_cache_size)- atomic_read(&buffermem_pages)) << (PAGE_SHIFT-10)); + printk("Cache memory: %6ldkB\n", + (page_cache_size - atomic_read(&buffermem_pages)) << (PAGE_SHIFT-10)); #ifdef CONFIG_SMP /* trylock does nothing on UP and so we could deadlock */ if (!spin_trylock(&lru_list_lock)) diff -urN vm-ref/fs/proc/proc_misc.c vm/fs/proc/proc_misc.c --- vm-ref/fs/proc/proc_misc.c Fri Mar 29 13:35:42 2002 +++ vm/fs/proc/proc_misc.c Fri Mar 29 18:44:01 2002 @@ -144,7 +144,7 @@ #define B(x) ((unsigned long long)(x) << PAGE_SHIFT) si_meminfo(&i); si_swapinfo(&i); - pg_size = atomic_read(&page_cache_size) - i.bufferram ; + pg_size = page_cache_size - i.bufferram; len = sprintf(page, " total: used: free: shared: buffers: cached:\n" "Mem: %8Lu %8Lu %8Lu %8Lu %8Lu %8Lu\n" diff -urN vm-ref/include/linux/mmzone.h vm/include/linux/mmzone.h --- vm-ref/include/linux/mmzone.h Fri Mar 29 13:35:50 2002 +++ vm/include/linux/mmzone.h Fri Mar 29 18:44:01 2002 @@ -41,7 +41,18 @@ spinlock_t lock; unsigned long free_pages; unsigned long pages_min, pages_low, pages_high; - int need_balance; + + /* + * The below fields are protected by different locks (or by + * no lock at all like need_balance), so they're longs to + * provide an atomic granularity against each other on + * all architectures. + */ + unsigned long need_balance; + /* protected by the pagemap_lru_lock */ + unsigned long nr_active_pages, nr_inactive_pages; + /* protected by the pagecache_lock */ + unsigned long nr_cache_pages; /* * free areas of different sizes diff -urN vm-ref/include/linux/pagemap.h vm/include/linux/pagemap.h --- vm-ref/include/linux/pagemap.h Fri Mar 29 13:35:50 2002 +++ vm/include/linux/pagemap.h Fri Mar 29 18:44:01 2002 @@ -45,7 +45,7 @@ #define PAGE_HASH_BITS (page_hash_bits) #define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS) -extern atomic_t page_cache_size; /* # of pages currently in the hash table */ +extern unsigned long page_cache_size; /* # of pages currently in the hash table */ extern struct page **page_hash_table; extern void page_cache_init(unsigned long); diff -urN vm-ref/include/linux/swap.h vm/include/linux/swap.h --- vm-ref/include/linux/swap.h Fri Mar 29 18:40:30 2002 +++ vm/include/linux/swap.h Fri Mar 29 18:44:24 2002 @@ -88,7 +88,7 @@ extern int nr_active_pages; extern int nr_inactive_pages; extern atomic_t nr_async_pages; -extern atomic_t page_cache_size; +extern unsigned long page_cache_size; extern atomic_t buffermem_pages; extern spinlock_cacheline_t pagecache_lock_cacheline; @@ -177,33 +177,45 @@ BUG(); \ } while (0) +extern void delta_nr_active_pages(struct page *page, long delta); +#define inc_nr_active_pages(page) delta_nr_active_pages(page, 1) +#define dec_nr_active_pages(page) delta_nr_active_pages(page, -1) + +extern void delta_nr_inactive_pages(struct page *page, long delta); +#define inc_nr_inactive_pages(page) delta_nr_inactive_pages(page, 1) +#define dec_nr_inactive_pages(page) delta_nr_inactive_pages(page, -1) + #define add_page_to_active_list(page) \ do { \ DEBUG_LRU_PAGE(page); \ SetPageActive(page); \ list_add(&(page)->lru, &active_list); \ - nr_active_pages++; \ + inc_nr_active_pages(page); \ } while (0) #define add_page_to_inactive_list(page) \ do { \ DEBUG_LRU_PAGE(page); \ list_add(&(page)->lru, &inactive_list); \ - nr_inactive_pages++; \ + inc_nr_inactive_pages(page); \ } while (0) #define del_page_from_active_list(page) \ do { \ list_del(&(page)->lru); \ ClearPageActive(page); \ - nr_active_pages--; \ + dec_nr_active_pages(page); \ } while (0) #define del_page_from_inactive_list(page) \ do { \ list_del(&(page)->lru); \ - nr_inactive_pages--; \ + dec_nr_inactive_pages(page); \ } while (0) + +extern void delta_nr_cache_pages(struct page *page, long delta); +#define inc_nr_cache_pages(page) delta_nr_cache_pages(page, 1) +#define dec_nr_cache_pages(page) delta_nr_cache_pages(page, -1) extern spinlock_t swaplock; diff -urN vm-ref/mm/filemap.c vm/mm/filemap.c --- vm-ref/mm/filemap.c Fri Mar 29 18:35:54 2002 +++ vm/mm/filemap.c Fri Mar 29 18:44:01 2002 @@ -43,7 +43,7 @@ * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli */ -atomic_t page_cache_size = ATOMIC_INIT(0); +unsigned long page_cache_size; unsigned int page_hash_bits; struct page **page_hash_table; @@ -80,7 +80,7 @@ next->pprev_hash = &page->next_hash; if (page->buffers) PAGE_BUG(page); - atomic_inc(&page_cache_size); + inc_nr_cache_pages(page); } static inline void add_page_to_inode_queue(struct address_space *mapping, struct page * page) @@ -110,7 +110,7 @@ next->pprev_hash = pprev; *pprev = next; page->pprev_hash = NULL; - atomic_dec(&page_cache_size); + dec_nr_cache_pages(page); } /* diff -urN vm-ref/mm/mmap.c vm/mm/mmap.c --- vm-ref/mm/mmap.c Fri Mar 29 18:35:55 2002 +++ vm/mm/mmap.c Fri Mar 29 18:44:01 2002 @@ -70,7 +70,7 @@ return 1; /* The page cache contains buffer pages these days.. */ - free = atomic_read(&page_cache_size); + free = page_cache_size; free += nr_free_pages(); free += nr_swap_pages; diff -urN vm-ref/mm/swap.c vm/mm/swap.c --- vm-ref/mm/swap.c Tue Jan 22 18:56:00 2002 +++ vm/mm/swap.c Fri Mar 29 18:44:01 2002 @@ -93,6 +93,78 @@ spin_unlock(&pagemap_lru_lock); } +/** + * delta_nr_active_pages: alter the number of active pages. + * + * @page: the page which is being activated/deactivated + * @delta: +1 for activation, -1 for deactivation + * + * Called under pagecache_lock + */ +void delta_nr_active_pages(struct page *page, long delta) +{ + pg_data_t *pgdat; + zone_t *classzone, *overflow; + + classzone = page_zone(page); + pgdat = classzone->zone_pgdat; + overflow = pgdat->node_zones + pgdat->nr_zones; + + while (classzone < overflow) { + classzone->nr_active_pages += delta; + classzone++; + } + nr_active_pages += delta; +} + +/** + * delta_nr_inactive_pages: alter the number of inactive pages. + * + * @page: the page which is being deactivated/activated + * @delta: +1 for deactivation, -1 for activation + * + * Called under pagecache_lock + */ +void delta_nr_inactive_pages(struct page *page, long delta) +{ + pg_data_t *pgdat; + zone_t *classzone, *overflow; + + classzone = page_zone(page); + pgdat = classzone->zone_pgdat; + overflow = pgdat->node_zones + pgdat->nr_zones; + + while (classzone < overflow) { + classzone->nr_inactive_pages += delta; + classzone++; + } + nr_inactive_pages += delta; +} + +/** + * delta_nr_cache_pages: alter the number of pages in the pagecache + * + * @page: the page which is being added/removed + * @delta: +1 for addition, -1 for removal + * + * Called under pagecache_lock + */ +void delta_nr_cache_pages(struct page *page, long delta) +{ + pg_data_t *pgdat; + zone_t *classzone, *overflow; + + classzone = page_zone(page); + pgdat = classzone->zone_pgdat; + overflow = pgdat->node_zones + pgdat->nr_zones; + + while (classzone < overflow) { + classzone->nr_cache_pages += delta; + classzone++; + } + page_cache_size += delta; +} + /* * Perform any setup for the swap system */