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 --- 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 #include +#include /* 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); } _