From: NeilBrown <neilb@cse.unsw.edu.au>

Create a slab cache for nfsv4 stateowners.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/nfsd/nfs4state.c       |   55 +++++++++++++++++++++++++++++++-------
 25-akpm/fs/nfsd/nfssvc.c          |    4 ++
 25-akpm/include/linux/nfsd/nfsd.h |    4 +-
 3 files changed, 51 insertions(+), 12 deletions(-)

diff -puN fs/nfsd/nfs4state.c~nfsd4-create-a-slab-cache-for-stateowners fs/nfsd/nfs4state.c
--- 25/fs/nfsd/nfs4state.c~nfsd4-create-a-slab-cache-for-stateowners	2005-03-07 23:55:13.000000000 -0800
+++ 25-akpm/fs/nfsd/nfs4state.c	2005-03-08 00:02:30.000000000 -0800
@@ -985,14 +985,38 @@ release_all_files(void)
 	}
 }
 
-/* should use a slab cache */
+kmem_cache_t *stateowner_slab = NULL;
+
+static int
+nfsd4_init_slabs(void)
+{
+	stateowner_slab = kmem_cache_create("nfsd4_stateowners",
+			sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
+	if (stateowner_slab == NULL) {
+		dprintk("nfsd4: out of memory while initializing nfsv4\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void
+nfsd4_free_slabs(void)
+{
+	int status = 0;
+
+	if (stateowner_slab)
+		status = kmem_cache_destroy(stateowner_slab);
+	stateowner_slab = NULL;
+	BUG_ON(status);
+}
+
 void
 nfs4_free_stateowner(struct kref *kref)
 {
 	struct nfs4_stateowner *sop =
 		container_of(kref, struct nfs4_stateowner, so_ref);
 	kfree(sop->so_owner.data);
-	kfree(sop);
+	kmem_cache_free(stateowner_slab, sop);
 	free_sowner++;
 }
 
@@ -1001,14 +1025,14 @@ alloc_stateowner(struct xdr_netobj *owne
 {
 	struct nfs4_stateowner *sop;
 
-	if ((sop = kmalloc(sizeof(struct nfs4_stateowner),GFP_KERNEL))) {
+	if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) {
 		if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {
 			memcpy(sop->so_owner.data, owner->data, owner->len);
 			sop->so_owner.len = owner->len;
 			kref_init(&sop->so_ref);
 			return sop;
 		} 
-		kfree(sop);
+		kmem_cache_free(stateowner_slab, sop);
 	}
 	return NULL;
 }
@@ -3129,14 +3153,12 @@ nfs4_check_open_reclaim(clientid_t *clid
  * Start and stop routines
  */
 
-void 
-nfs4_state_init(void)
+static void
+__nfs4_state_init(void)
 {
 	int i;
 	time_t grace_time;
 
-	if (nfs4_init)
-		return;
 	if (!nfs4_reclaim_init) {
 		for (i = 0; i < CLIENT_HASH_SIZE; i++)
 			INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
@@ -3180,7 +3202,21 @@ nfs4_state_init(void)
 	grace_end = boot_time + grace_time;
 	INIT_WORK(&laundromat_work,laundromat_main, NULL);
 	schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
+}
+
+int
+nfs4_state_init(void)
+{
+	int status;
+
+	if (nfs4_init)
+		return 0;
+	status = nfsd4_init_slabs();
+	if (status)
+		return status;
+	__nfs4_state_init();
 	nfs4_init = 1;
+	return 0;
 }
 
 int
@@ -3253,6 +3289,7 @@ nfs4_state_shutdown(void)
 	nfs4_lock_state();
 	nfs4_release_reclaim();
 	__nfs4_state_shutdown();
+	nfsd4_free_slabs();
 	nfs4_unlock_state();
 }
 
@@ -3305,7 +3342,7 @@ nfs4_reset_lease(time_t leasetime)
 	}
 init_state:
 	__nfs4_state_shutdown();
-	nfs4_state_init();
+	__nfs4_state_init();
 	nfs4_unlock_state();
 }
 
diff -puN fs/nfsd/nfssvc.c~nfsd4-create-a-slab-cache-for-stateowners fs/nfsd/nfssvc.c
--- 25/fs/nfsd/nfssvc.c~nfsd4-create-a-slab-cache-for-stateowners	2005-03-07 23:55:13.000000000 -0800
+++ 25-akpm/fs/nfsd/nfssvc.c	2005-03-08 00:02:26.000000000 -0800
@@ -92,7 +92,9 @@ nfsd_svc(unsigned short port, int nrserv
 	
 	/* Readahead param cache - will no-op if it already exists */
 	error =	nfsd_racache_init(2*nrservs);
-	nfs4_state_init();
+	if (error<0)
+		goto out;
+	error = nfs4_state_init();
 	if (error<0)
 		goto out;
 	if (!nfsd_serv) {
diff -puN include/linux/nfsd/nfsd.h~nfsd4-create-a-slab-cache-for-stateowners include/linux/nfsd/nfsd.h
--- 25/include/linux/nfsd/nfsd.h~nfsd4-create-a-slab-cache-for-stateowners	2005-03-07 23:55:13.000000000 -0800
+++ 25-akpm/include/linux/nfsd/nfsd.h	2005-03-08 00:02:42.000000000 -0800
@@ -129,12 +129,12 @@ int		nfsd_permission(struct svc_export *
  * NFSv4 State
  */
 #ifdef CONFIG_NFSD_V4
-void nfs4_state_init(void);
+int nfs4_state_init(void);
 void nfs4_state_shutdown(void);
 time_t nfs4_lease_time(void);
 void nfs4_reset_lease(time_t leasetime);
 #else
-void static inline nfs4_state_init(void){}
+int static inline nfs4_state_init(void){return 0;}
 void static inline nfs4_state_shutdown(void){}
 time_t static inline nfs4_lease_time(void){return 0;}
 void static inline nfs4_reset_lease(time_t leasetime){}
_