Subject: Slab defrag: buffer_heads Limited defragmentation support for buffer heads. Simply try to free the buffers in a sparsely populated slab page. Signed-off-by: Christoph Lameter --- fs/buffer.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) Index: linux-2.6/fs/buffer.c =================================================================== --- linux-2.6.orig/fs/buffer.c 2007-07-29 13:59:36.000000000 -0700 +++ linux-2.6/fs/buffer.c 2007-07-29 14:24:47.000000000 -0700 @@ -3003,12 +3003,69 @@ static int buffer_cpu_notify(struct noti return NOTIFY_OK; } +/* + * Get references on buffers. + * + * We obtain references on the page that uses the buffer. v[i] will point to + * the corresponding page after get_buffers() is through. + * + * We are safe from the underlying page being removed simply by doing + * a get_page_unless_zero. The buffer head removal may race at will. + * try_to_free_buffes will later take appropriate locks to remove the + * buffers if they are still there. + * + * TODO: Write out dirty buffers to increase the chance of kick_buffers + * to be successful. + */ +static void *get_buffers(struct kmem_cache *s, int nr, void **v) +{ + struct page *page; + struct buffer_head *bh; + int i; + + for (i = 0; i < nr; i++) { + bh = v[i]; + page = bh->b_page; + if (page && PagePrivate(page) && get_page_unless_zero(page)) + v[i] = page; + else + v[i] = NULL; + } + return NULL; +} + +/* + * Despite its name: kick_buffers operates on a list of pointers to + * page structs that was setup by get_buffer + */ +static void kick_buffers(struct kmem_cache *s, int nr, void **v, + void *private) +{ + struct page *page; + int i; + + for (i = 0; i < nr; i++) { + page = v[i]; + + if (!page) + continue; + + if (!TestSetPageLocked(page)) { + if (PagePrivate(page)) + try_to_free_buffers(page); + unlock_page(page); + } + put_page(page); + } +} + void __init buffer_init(void) { int nrpages; bh_cachep = KMEM_CACHE(buffer_head, SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); + kmem_cache_setup_defrag(bh_cachep, get_buffers, kick_buffers); /* * Limit the bh occupancy to 10% of ZONE_NORMAL