

Reference the common credcache from cloned rpc clients. Add ref counting to
know when to free the cache. Free the cache in rpc_destroy_client.

Signed-off-by: Andy Adamson <andros@citi.umich.edu>
---


diff -puN include/linux/sunrpc/auth.h~rpc-common-credcache-ref-count include/linux/sunrpc/auth.h
--- linux-2.6.18-rc5/include/linux/sunrpc/auth.h~rpc-common-credcache-ref-count	2006-10-17 11:25:30.000000000 -0400
+++ linux-2.6.18-rc5-andros/include/linux/sunrpc/auth.h	2006-10-17 12:15:06.000000000 -0400
@@ -16,6 +16,7 @@
 #include <linux/sunrpc/xdr.h>
 
 #include <asm/atomic.h>
+#include <linux/kref.h>
 
 /* size of the nodename buffer */
 #define UNX_MAXNODENAME	32
@@ -60,8 +61,23 @@ struct rpc_cred {
 #define RPC_CREDCACHE_MASK	(RPC_CREDCACHE_NR - 1)
 struct rpc_cred_cache {
 	struct hlist_head	hashtable[RPC_CREDCACHE_NR];
+	struct kref		ref;
 };
 
+static inline void
+rpcauth_get_ccache(struct rpc_cred_cache *cache)
+{
+	kref_get(&cache->ref);
+}
+
+void    rpcauth_free_ccache(struct kref *);
+
+static inline void
+rpcauth_put_ccache(struct rpc_cred_cache *cache)
+{
+	kref_put(&cache->ref, rpcauth_free_ccache);
+}
+
 struct rpc_auth {
 	unsigned int		au_cslack;	/* call cred size estimate */
 				/* guess at number of u32's auth adds before
@@ -143,7 +159,7 @@ int			rpcauth_refreshcred(struct rpc_tas
 void			rpcauth_invalcred(struct rpc_task *);
 int			rpcauth_uptodatecred(struct rpc_task *);
 int			rpcauth_init_credcache(struct rpc_clnt *);
-void			rpcauth_free_credcache(struct rpc_auth *);
+void			rpcauth_free_credcache(struct rpc_clnt *);
 
 static inline
 struct rpc_cred *	get_rpccred(struct rpc_cred *cred)
diff -puN net/sunrpc/clnt.c~rpc-common-credcache-ref-count net/sunrpc/clnt.c
--- linux-2.6.18-rc5/net/sunrpc/clnt.c~rpc-common-credcache-ref-count	2006-10-17 11:25:30.000000000 -0400
+++ linux-2.6.18-rc5-andros/net/sunrpc/clnt.c	2006-10-17 12:13:50.000000000 -0400
@@ -272,8 +272,6 @@ rpc_clone_client(struct rpc_clnt *clnt)
 	if (!IS_ERR(new->cl_dentry))
 		dget(new->cl_dentry);
 	rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
-	if (new->cl_auth)
-		atomic_inc(&new->cl_auth->au_count);
 	new->cl_metrics = rpc_alloc_iostats(clnt);
 	return new;
 out_no_clnt:
@@ -327,10 +325,6 @@ rpc_destroy_client(struct rpc_clnt *clnt
 
 	dprintk("RPC: destroying %s client for %s\n",
 			clnt->cl_protname, clnt->cl_server);
-	if (clnt->cl_auth) {
-		rpcauth_destroy(clnt->cl_auth);
-		clnt->cl_auth = NULL;
-	}
 	if (clnt->cl_parent != clnt) {
 		if (!IS_ERR(clnt->cl_dentry))
 			dput(clnt->cl_dentry);
@@ -345,6 +339,8 @@ rpc_destroy_client(struct rpc_clnt *clnt
 		xprt_destroy(clnt->cl_xprt);
 		clnt->cl_xprt = NULL;
 	}
+	if (clnt->cl_credcache)
+		rpcauth_free_credcache(clnt);
 	if (clnt->cl_server != clnt->cl_inline_name)
 		kfree(clnt->cl_server);
 out_free:
diff -puN net/sunrpc/auth.c~rpc-common-credcache-ref-count net/sunrpc/auth.c
--- linux-2.6.18-rc5/net/sunrpc/auth.c~rpc-common-credcache-ref-count	2006-10-17 11:25:30.000000000 -0400
+++ linux-2.6.18-rc5-andros/net/sunrpc/auth.c	2006-10-17 12:15:06.000000000 -0400
@@ -83,11 +83,8 @@ rpcauth_create(rpc_authflavor_t pseudofl
 	auth = ops->create(clnt, pseudoflavor);
 	if (IS_ERR(auth))
 		return auth;
-	if (clnt->cl_auth)
-		rpcauth_destroy(clnt->cl_auth);
 	auth->au_credcache = clnt->cl_credcache;
 	clnt->cl_auth = auth;
-
 out:
 	return auth;
 }
@@ -117,6 +114,7 @@ rpcauth_init_credcache(struct rpc_clnt *
 	err = 0;
 	for (i = 0; i < RPC_CREDCACHE_NR; i++)
 		INIT_HLIST_HEAD(&new->hashtable[i]);
+	kref_init(&new->ref);
 done:
 	clnt->cl_credcache = new;
 	return err;
@@ -142,9 +140,20 @@ void rpcauth_destroy_credlist(struct hli
  * that are not referenced.
  */
 void
-rpcauth_free_credcache(struct rpc_auth *auth)
+rpcauth_free_credcache(struct rpc_clnt *clnt)
 {
-	struct rpc_cred_cache *cache = auth->au_credcache;
+	int remove = atomic_read(&clnt->cl_credcache->ref.refcount);
+	rpcauth_put_ccache(clnt->cl_credcache);
+	if (remove == 1){
+		clnt->cl_auth = NULL;
+		clnt->cl_credcache = NULL;
+	}
+}
+
+void
+rpcauth_free_ccache(struct kref *ref)
+{
+	struct rpc_cred_cache *cache = container_of(ref, struct rpc_cred_cache, ref);
 	HLIST_HEAD(free);
 	struct hlist_node *pos, *next;
 	struct rpc_cred	*cred;
@@ -160,6 +169,7 @@ rpcauth_free_credcache(struct rpc_auth *
 	}
 	spin_unlock(&rpc_credcache_lock);
 	rpcauth_destroy_credlist(&free);
+	kfree(cache);
 }
 
 static void
diff -puN net/sunrpc/auth_unix.c~rpc-common-credcache-ref-count net/sunrpc/auth_unix.c
--- linux-2.6.18-rc5/net/sunrpc/auth_unix.c~rpc-common-credcache-ref-count	2006-10-17 11:25:30.000000000 -0400
+++ linux-2.6.18-rc5-andros/net/sunrpc/auth_unix.c	2006-10-17 12:15:06.000000000 -0400
@@ -48,7 +48,6 @@ static void
 unx_destroy(struct rpc_auth *auth)
 {
 	dprintk("RPC: destroying UNIX authenticator %p\n", auth);
-	rpcauth_free_credcache(auth);
 }
 
 /*
diff -puN net/sunrpc/auth_gss/auth_gss.c~rpc-common-credcache-ref-count net/sunrpc/auth_gss/auth_gss.c
--- linux-2.6.18-rc5/net/sunrpc/auth_gss/auth_gss.c~rpc-common-credcache-ref-count	2006-10-17 11:25:30.000000000 -0400
+++ linux-2.6.18-rc5-andros/net/sunrpc/auth_gss/auth_gss.c	2006-10-17 12:16:32.000000000 -0400
@@ -340,6 +340,7 @@ gss_release_msg(struct gss_upcall_msg *g
 	BUG_ON(!list_empty(&gss_msg->list));
 	if (gss_msg->ctx != NULL)
 		gss_put_ctx(gss_msg->ctx);
+	rpcauth_put_ccache(gss_msg->auth->rpc_auth.au_credcache);
 	kfree(gss_msg);
 }
 
@@ -526,6 +527,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, 
 		}
 	} else
 		gss_release_msg(gss_new);
+	rpcauth_get_ccache(clnt->cl_credcache);
 	return gss_msg;
 }
 
@@ -912,7 +914,6 @@ gss_destroy(struct rpc_auth *auth)
 	gss_auth->dentry = NULL;
 	gss_mech_put(gss_auth->mech);
 
-	rpcauth_free_credcache(auth);
 	kfree(gss_auth);
 	module_put(THIS_MODULE);
 }
_
