[PATCH] Implementation of pagecache.max and buffermem.max

Larry Woodman (woodman@missioncriticallinux.com)
Mon, 01 Nov 1999 17:40:34 -0500


This is a multi-part message in MIME format.
--------------5F0150A9C2489B9609AF8B94
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Currently the /proc/sys/vm/pagecache and /proc/sys/vm/buffermem
interfaces allow
administrators to configure maximum percentages of physical memory that
the
pagecache and buffermem are allowed to consume but the kernel ignores
these
parameters. This results in poor system performance when large files
are being
read, written or copied. This patch limits the percentage of physical
memory that
can be consumed by both the pagecache and buffermem. For example:

# echo 2 15 25 > /proc/sys/vm/pagecache
# echo 2 10 25 > /proc/sys/vm/buffermem

limits both the pagecache and buffermem to 25% of the system's physical
memory.
These can be changed(both increased and decreased) on the fly without
detrimental
side effects.

Note: This patch only implements the minimum and maximum percent
parameters.
I am working on a fix for the borrow percent parameters.

Larry Woodman

--------------5F0150A9C2489B9609AF8B94
Content-Type: text/plain; charset=us-ascii;
name="patch-2.2.13.larry"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="patch-2.2.13.larry"

diff -u --recursive --new-file linux-2.2.13.vanilla/fs/buffer.c linux-2.2.13.larry/fs/buffer.c
--- linux-2.2.13.vanilla/fs/buffer.c Mon Aug 9 15:04:40 1999
+++ linux-2.2.13.larry/fs/buffer.c Mon Nov 1 13:33:25 1999
@@ -1349,6 +1349,10 @@
return 0;
}

+extern void shrink_buffer_cache(int);
+#define buffermem_over_max() (buffermem/PAGE_SIZE < buffer_mem.max_percent*num_physpages/100) ? \
+ 0 : (buffermem/PAGE_SIZE-buffer_mem.max_percent*num_physpages/100)
+
/*
* Try to increase the number of buffers available: the size argument
* is used to determine what kind of buffers we want.
@@ -1359,6 +1363,7 @@
struct buffer_head *bh, *tmp;
struct buffer_head * insert_point;
int isize;
+ int over;

if ((size & 511) || (size > PAGE_SIZE)) {
printk("VFS: grow_buffers: size = %d\n",size);
@@ -1398,6 +1403,9 @@
free_list[isize] = bh;
mem_map[MAP_NR(page)].buffers = bh;
buffermem += PAGE_SIZE;
+ if ((over = buffermem_over_max()) > 0) {
+ shrink_buffer_cache(over);
+ }
return 1;
}

diff -u --recursive --new-file linux-2.2.13.vanilla/mm/filemap.c linux-2.2.13.larry/mm/filemap.c
--- linux-2.2.13.vanilla/mm/filemap.c Mon Nov 1 17:12:55 1999
+++ linux-2.2.13.larry/mm/filemap.c Mon Nov 1 13:36:55 1999
@@ -212,6 +212,70 @@
return 0;
}

+void shrink_buffer_cache(long over)
+{
+ static unsigned long clock = 0;
+ long limit = num_physpages;
+ struct page * page;
+
+ page = mem_map + clock;
+ do {
+ page++;
+ clock++;
+ if (clock >= max_mapnr) {
+ clock = 0;
+ page = mem_map;
+ }
+
+ /* is it a buffer page? */
+ if ((page->buffers)) {
+
+ if (PageLocked(page) || PageDMA(page) ||
+ (test_and_clear_bit(PG_referenced, &page->flags)) ||
+ PageSwapCache(page) || (atomic_read(&page->count) != 1))
+ continue;
+
+ if(!try_to_free_buffers(page)) {
+ continue;
+ } else
+ over--;
+ }
+ limit--;
+ } while ((over > 0) && (limit > 0));
+
+}
+
+void shrink_page_cache(long over)
+{
+ static unsigned long clock = 0;
+ long limit = num_physpages;
+ struct page * page;
+
+ page = mem_map + clock;
+ do {
+ page++;
+ clock++;
+ if (clock >= max_mapnr) {
+ clock = 0;
+ page = mem_map;
+ }
+
+ /* is it a page-cache page? */
+ if ((page->inode) && (page->inode != &swapper_inode)) {
+
+ if (PageLocked(page) || PageDMA(page) ||
+ (test_and_clear_bit(PG_referenced, &page->flags)) ||
+ PageSwapCache(page) || (atomic_read(&page->count) != 1))
+ continue;
+
+ remove_inode_page(page);
+ over--;
+ }
+ limit--;
+ } while ((over > 0) && (limit > 0));
+
+}
+
/*
* Update a page cache copy, when we're doing a "write()" system call
* See also "update_vm_cache()".
@@ -268,16 +332,23 @@
update_vm_cache_conditional(inode, pos, buf, count, 0);
}

+extern unsigned long swap_cache_pages;
+#define pgcache_over_max() ((page_cache_size-swap_cache_pages) <= page_cache.max_percent*num_physpages/100) ? \
+ 0 : ((page_cache_size-swap_cache_pages)-page_cache.max_percent*num_physpages/100)

static inline void add_to_page_cache(struct page * page,
struct inode * inode, unsigned long offset,
struct page **hash)
{
+ int over;
+
atomic_inc(&page->count);
page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced);
page->offset = offset;
add_page_to_inode_queue(inode, page);
__add_page_to_hash_queue(page, hash);
+ if ((over = pgcache_over_max()) > 0)
+ shrink_page_cache(over);
}

/*
diff -u --recursive --new-file linux-2.2.13.vanilla/mm/swap_state.c linux-2.2.13.larry/mm/swap_state.c
--- linux-2.2.13.vanilla/mm/swap_state.c Wed Jan 13 12:54:50 1999
+++ linux-2.2.13.larry/mm/swap_state.c Mon Nov 1 13:32:15 1999
@@ -42,6 +42,8 @@
}
#endif

+unsigned long swap_cache_pages = 0;
+
int add_to_swap_cache(struct page *page, unsigned long entry)
{
#ifdef SWAP_CACHE_INFO
@@ -67,6 +69,7 @@
page->offset = entry;
add_page_to_hash_queue(page, &swapper_inode, entry);
add_page_to_inode_queue(&swapper_inode, page);
+ swap_cache_pages++;
return 1;
}

@@ -194,6 +197,7 @@
#endif
PageClearSwapCache (page);
remove_inode_page(page);
+ swap_cache_pages--;
}


--------------5F0150A9C2489B9609AF8B94--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/