diff -urN 2.4.19pre8/arch/sparc/kernel/sys_sunos.c zone-acc/arch/sparc/kernel/sys_sunos.c
--- 2.4.19pre8/arch/sparc/kernel/sys_sunos.c	Tue Jan 22 18:52:53 2002
+++ zone-acc/arch/sparc/kernel/sys_sunos.c	Fri May  3 20:18:59 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 2.4.19pre8/arch/sparc64/kernel/sys_sunos32.c zone-acc/arch/sparc64/kernel/sys_sunos32.c
--- 2.4.19pre8/arch/sparc64/kernel/sys_sunos32.c	Fri May  3 02:12:07 2002
+++ zone-acc/arch/sparc64/kernel/sys_sunos32.c	Fri May  3 20:18:59 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 2.4.19pre8/fs/buffer.c zone-acc/fs/buffer.c
--- 2.4.19pre8/fs/buffer.c	Fri May  3 02:12:18 2002
+++ zone-acc/fs/buffer.c	Fri May  3 20:18:59 2002
@@ -2686,10 +2686,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 2.4.19pre8/fs/proc/proc_misc.c zone-acc/fs/proc/proc_misc.c
--- 2.4.19pre8/fs/proc/proc_misc.c	Fri May  3 02:12:18 2002
+++ zone-acc/fs/proc/proc_misc.c	Fri May  3 20:18:59 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 2.4.19pre8/include/linux/mmzone.h zone-acc/include/linux/mmzone.h
--- 2.4.19pre8/include/linux/mmzone.h	Fri May  3 02:12:28 2002
+++ zone-acc/include/linux/mmzone.h	Fri May  3 20:18:59 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 2.4.19pre8/include/linux/pagemap.h zone-acc/include/linux/pagemap.h
--- 2.4.19pre8/include/linux/pagemap.h	Mon Feb 25 22:05:09 2002
+++ zone-acc/include/linux/pagemap.h	Fri May  3 20:18:59 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 2.4.19pre8/include/linux/swap.h zone-acc/include/linux/swap.h
--- 2.4.19pre8/include/linux/swap.h	Fri May  3 02:12:28 2002
+++ zone-acc/include/linux/swap.h	Fri May  3 20:19:18 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;
@@ -176,33 +176,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 2.4.19pre8/mm/filemap.c zone-acc/mm/filemap.c
--- 2.4.19pre8/mm/filemap.c	Fri May  3 02:12:29 2002
+++ zone-acc/mm/filemap.c	Fri May  3 20:18:59 2002
@@ -42,7 +42,7 @@
  * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli <andrea@suse.de>
  */
 
-atomic_t page_cache_size = ATOMIC_INIT(0);
+unsigned long page_cache_size;
 unsigned int page_hash_bits;
 struct page **page_hash_table;
 
@@ -79,7 +79,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)
@@ -109,7 +109,7 @@
 		next->pprev_hash = pprev;
 	*pprev = next;
 	page->pprev_hash = NULL;
-	atomic_dec(&page_cache_size);
+	dec_nr_cache_pages(page);
 }
 
 /*
diff -urN 2.4.19pre8/mm/mmap.c zone-acc/mm/mmap.c
--- 2.4.19pre8/mm/mmap.c	Fri May  3 02:12:29 2002
+++ zone-acc/mm/mmap.c	Fri May  3 20:18:59 2002
@@ -69,7 +69,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 2.4.19pre8/mm/swap.c zone-acc/mm/swap.c
--- 2.4.19pre8/mm/swap.c	Tue Jan 22 18:56:00 2002
+++ zone-acc/mm/swap.c	Fri May  3 20:18:59 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
  */
