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)

_