Skip to contentSkip to conversation

aa-110-zone_accounting

PATCH Andrew Morton 4 participants 5 messages Mar 20, 2002

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

1: page_cache_size is no longer an atomic type - it's now just an
unsigned long. It's always altered under pagecache_lock.

2: accounting for number of pages on active LRU, number of pages on
inactive LRU pages and total page cache size is now per-classzone rather than global.

3: Various macros to hide the above mechanism.

4: The use of the per-classzone counters was introduced in
aa-096-swap_out. This match actually makes them right, and the VM starts working again.

Andrea originally had the per-zone and global nr_inactive_pages, nr_active_pages and page_cache_size accounting implemented as macros in swap.h. Linus described these as "macros from hell", so the hint was taken and I implemented them as functions in swap.c.

These page-accounting functions require page_cache_lock for atomicity. That's fine for 2.4 but won't cut it with the radix-tree pagecache which is 2.5-probable.

For ratcache, we'll need to turn these into per-zone, per-cpu counters, as I did in the delayed-allocate locked- and dirty- page accounting code. That works OK.

=====================================

arch/sparc64/kernel/sys_sunos32.c renamed from arch/sparc64/kernel/sys_sunos32.c~aa-110-zone_accounting +1 -1
@@ -157,7 +157,7 @@ asmlinkage int sunos_brk(u32 baddr)
 	 * 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;
arch/sparc/kernel/sys_sunos.c renamed from arch/sparc/kernel/sys_sunos.c~aa-110-zone_accounting +1 -1
@@ -193,7 +193,7 @@ asmlinkage int sunos_brk(unsigned long b
 	 * 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;
fs/buffer.c renamed from fs/buffer.c~aa-110-zone_accounting +3 -3
@@ -2738,10 +2738,10 @@ void show_buffers(void)
 #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))
fs/proc/proc_misc.c renamed from fs/proc/proc_misc.c~aa-110-zone_accounting +1 -1
@@ -142,7 +142,7 @@ static int meminfo_read_proc(char *page,
 #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"
include/linux/pagemap.h renamed from include/linux/pagemap.h~aa-110-zone_accounting +1 -1
@@ -45,7 +45,7 @@ extern unsigned int page_hash_bits;
 #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);
include/linux/swap.h renamed from include/linux/swap.h~aa-110-zone_accounting +17 -5
@@ -88,7 +88,7 @@ extern unsigned int nr_free_buffer_pages
 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_t pagecache_lock;
 extern void __remove_inode_page(struct page *);
@@ -173,33 +173,45 @@ do {						\
 		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;
 
mm/filemap.c renamed from mm/filemap.c~aa-110-zone_accounting +3 -3
@@ -43,7 +43,7 @@
  * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli <[email protected]>
  */
 
-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 @@ static void add_page_to_hash_queue(struc
 		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 @@ static inline void remove_page_from_hash
 		next->pprev_hash = pprev;
 	*pprev = next;
 	page->pprev_hash = NULL;
-	atomic_dec(&page_cache_size);
+	dec_nr_cache_pages(page);
 }
 
 /*
mm/mmap.c renamed from mm/mmap.c~aa-110-zone_accounting +1 -1
@@ -69,7 +69,7 @@ int vm_enough_memory(long pages)
 	    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;
 
mm/swap.c renamed from mm/swap.c~aa-110-zone_accounting +72 -0

78 lines not on this page · raw message

-

#1 lore raw

mm/swap.c void lru_cache_del(struct page * page) · line 111

Quoted 8 lines
mm/swap.c renamed from mm/swap.c~aa-110-zone_accounting +8 -0
+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;

Double-underscroes for local variables are very bad style. Could you change this?

#2 lore raw
In reply to Andrew Morton
Quoted 3 lines · Andrew Morton

4: The use of the per-classzone counters was introduced in
aa-096-swap_out. This match actually makes them right, and the VM starts working again.

Might be desirable to merge these into a single patch. The 096 and 110 patches are two sides of a single coin as newrly as I can tell.

Just my opinion, to prevent any possibility of someone using one without the other and winding up without functional VM.

Signature · 3 lines
bill davidsen <[email protected]>
  CTO, TMR Associates, Inc
Doing interesting things with little computers since 1979.
#3 lore raw
In reply to Andrew Morton
Quoted 2 lines · Andrew Morton

1: page_cache_size is no longer an atomic type - it's now just an
unsigned long. It's always altered under pagecache_lock.

Is this change worth it ? This code will have to be changed
back in any patch trying to fine-grain the pagecache lock...

Alternatively, maybe we should hide the page_cache_size behind magic macros too, so it's easier to change the underlying data structure(s).

regards,

Rik

Signature · 3 lines
Bravely reimplemented by the knights who say "NIH".

http://www.surriel.com/		http://distro.conectiva.com/
#4 lore raw
In reply to Andrew Morton
Quoted 8 lines · Rik van Riel
Quoted 2 lines · Andrew Morton

1: page_cache_size is no longer an atomic type - it's now just an
unsigned long. It's always altered under pagecache_lock.

Is this change worth it ? This code will have to be changed
back in any patch trying to fine-grain the pagecache lock...

Yes, it's the right change. Changes to page_cache_size always occur at the same time as changes to the per-zone accounting. So the locking is shared and it all nestles nicely.

In the longer-term we don't want that atomic_t either. We need to avoid global and even per-zone atomic_t's and locks.

Quoted 3 lines

Alternatively, maybe we should hide the page_cache_size behind magic macros too, so it's easier to change the underlying data structure(s).

I currently have:

+extern struct page_state {

+       unsigned long nr_dirty;
+       unsigned long nr_locked;
+       unsigned long nr_pagecache;

+} ____cacheline_aligned page_states[NR_CPUS]; +
+extern void get_page_state(struct page_state *ret);

-