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 | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) Index: linux-2.6.22-rc6-mm1/fs/buffer.c =================================================================== --- linux-2.6.22-rc6-mm1.orig/fs/buffer.c 2007-07-04 11:14:01.000000000 -0700 +++ linux-2.6.22-rc6-mm1/fs/buffer.c 2007-07-04 17:23:02.000000000 -0700 @@ -3078,12 +3078,75 @@ 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); + } +} + +static struct kmem_cache_ops buffer_head_kmem_cache_ops = { + .get = get_buffers, + .kick = kick_buffers, +}; + + void __init buffer_init(void) { int nrpages; - bh_cachep = KMEM_CACHE(buffer_head, - SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); + bh_cachep = KMEM_CACHE_OPS(buffer_head, + SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD, + &buffer_head_kmem_cache_ops); /* * Limit the bh occupancy to 10% of ZONE_NORMAL -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/