ext3 allocate and frees at least one handle structure for each system call. kmalloc and kfree are apparent in the profiles. Adding a slab cache for these objects takes the overhead for a write() from 1.63 microseconds down to 1.56. fs/jbd/journal.c | 26 ++++++++++++++++++++++++++ fs/jbd/transaction.c | 8 ++++---- include/linux/jbd.h | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff -puN fs/jbd/transaction.c~ext3-handle-cache fs/jbd/transaction.c --- 25/fs/jbd/transaction.c~ext3-handle-cache 2003-03-22 03:14:38.000000000 -0800 +++ 25-akpm/fs/jbd/transaction.c 2003-03-22 03:14:38.000000000 -0800 @@ -211,10 +211,10 @@ repeat_locked: /* Allocate a new handle. This should probably be in a slab... */ static handle_t *new_handle(int nblocks) { - handle_t *handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS); + handle_t *handle = jbd_alloc_handle(GFP_NOFS); if (!handle) return NULL; - memset(handle, 0, sizeof (handle_t)); + memset(handle, 0, sizeof(*handle)); handle->h_buffer_credits = nblocks; handle->h_ref = 1; INIT_LIST_HEAD(&handle->h_jcb); @@ -258,7 +258,7 @@ handle_t *journal_start(journal_t *journ err = start_this_handle(journal, handle); if (err < 0) { - kfree(handle); + jbd_free_handle(handle); current->journal_info = NULL; return ERR_PTR(err); } @@ -1402,7 +1402,7 @@ int journal_stop(handle_t *handle) if (handle->h_sync && !(current->flags & PF_MEMALLOC)) log_wait_commit(journal, tid); } - kfree(handle); + jbd_free_handle(handle); return err; } diff -puN include/linux/jbd.h~ext3-handle-cache include/linux/jbd.h --- 25/include/linux/jbd.h~ext3-handle-cache 2003-03-22 03:14:38.000000000 -0800 +++ 25-akpm/include/linux/jbd.h 2003-03-22 03:14:38.000000000 -0800 @@ -788,6 +788,21 @@ extern void journal_remove_journal_head( extern void __journal_remove_journal_head(struct buffer_head *bh); extern void journal_unlock_journal_head(struct journal_head *jh); +/* + * handle management + */ +extern kmem_cache_t *jbd_handle_cache; + +static inline handle_t *jbd_alloc_handle(int gfp_flags) +{ + return kmem_cache_alloc(jbd_handle_cache, gfp_flags); +} + +static inline void jbd_free_handle(handle_t *handle) +{ + kmem_cache_free(jbd_handle_cache, handle); +} + /* Primary revoke support */ #define JOURNAL_REVOKE_DEFAULT_HASH 256 extern int journal_init_revoke(journal_t *, int); diff -puN fs/jbd/journal.c~ext3-handle-cache fs/jbd/journal.c --- 25/fs/jbd/journal.c~ext3-handle-cache 2003-03-22 03:14:38.000000000 -0800 +++ 25-akpm/fs/jbd/journal.c 2003-03-22 03:14:38.000000000 -0800 @@ -1907,6 +1907,29 @@ static void __exit remove_jbd_proc_entry #endif +kmem_cache_t *jbd_handle_cache; + +static int __init journal_init_handle_cache(void) +{ + jbd_handle_cache = kmem_cache_create("journal_handle", + sizeof(handle_t), + 0, /* offset */ + 0, /* flags */ + NULL, /* ctor */ + NULL); /* dtor */ + if (jbd_handle_cache == NULL) { + printk(KERN_EMERG "JBD: failed to create handle cache\n"); + return -ENOMEM; + } + return 0; +} + +static void journal_destroy_handle_cache(void) +{ + if (jbd_handle_cache) + kmem_cache_destroy(jbd_handle_cache); +} + /* * Module startup and shutdown */ @@ -1918,6 +1941,8 @@ static int __init journal_init_caches(vo ret = journal_init_revoke_caches(); if (ret == 0) ret = journal_init_journal_head_cache(); + if (ret == 0) + ret = journal_init_handle_cache(); return ret; } @@ -1925,6 +1950,7 @@ static void journal_destroy_caches(void) { journal_destroy_revoke_caches(); journal_destroy_journal_head_cache(); + journal_destroy_handle_cache(); } static int __init journal_init(void) _