Currently, a single hash algorithm is used to hash the auth_cred
for lookup in the credcache for all rpc_auth flavors. Only the
uid is included in the value to be hashed.
For AUTH_SYS, rpc_creds created with the same uid but different
gids will all go on the same hash chain. In certain usage patterns,
such as the following, this can lead to extremely long hash chains
and slow performance for certain uids.
for (i = 0 ; i < 100000 ; i++) {
setregid(-1, i);
stat(path, &st);
}
With AUTH_SYS, in order to distribute the rpc_creds more evenly
throughout the cache, we want to include the gid in the hash.
However, since the gid is not relevant or appropriate for all
auth flavors, we need to provide hash functions specific to each
auth flavor. Do this by adding a 'hash_cred' function to the
rpc_authops stuct, and having rpcauth_lookup_credcache call a
hash function created for each flavor.
As a performance comparison for unix_auth, with a credcache
containing 100,000 entries, hashing both the uid and gid reduces
the time to complete an 'ls' of a single directory containing 1000
files from over 8 1/2 minutes to 4 1/2 seconds.
Signed-off-by: Frank Sorenson <[email protected]>
Frank Sorenson (5):
sunrpc: add hash_cred() function to rpc_authops struct
sunrpc: add generic_auth hash_cred() function
sunrpc: add auth_unix hash_cred() function
sunrpc: add RPCSEC_GSS hash_cred() function
sunrpc: replace generic auth_cred hash with auth-specific function
include/linux/sunrpc/auth.h | 1 +
net/sunrpc/auth.c | 2 +-
net/sunrpc/auth_generic.c | 9 +++++++++
net/sunrpc/auth_gss/auth_gss.c | 7 +++++++
net/sunrpc/auth_unix.c | 9 +++++++++
5 files changed, 27 insertions(+), 1 deletion(-)
--
2.5.5
Currently, a single hash algorithm is used to hash the auth_cred for
the credcache for all rpc_auth types. Add a hash_cred() function to
the rpc_authops struct to allow a hash function specific to each
auth flavor.
Signed-off-by: Frank Sorenson <[email protected]>
---
include/linux/sunrpc/auth.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 4ccf184..b1bc62b 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -131,6 +131,7 @@ struct rpc_authops {
struct rpc_auth * (*create)(struct rpc_auth_create_args *, struct rpc_clnt *);
void (*destroy)(struct rpc_auth *);
+ int (*hash_cred)(struct auth_cred *, unsigned int);
struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int, gfp_t);
int (*list_pseudoflavors)(rpc_authflavor_t *, int);
--
2.5.5
Add a hash_cred() function for generic_auth, using both the
uid and gid from the auth_cred.
Signed-off-by: Frank Sorenson <[email protected]>
---
net/sunrpc/auth_generic.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 1682195..0494513 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -78,6 +78,14 @@ static struct rpc_cred *generic_bind_cred(struct rpc_task *task,
return auth->au_ops->lookup_cred(auth, acred, lookupflags);
}
+static int
+generic_hash_cred(struct auth_cred *acred, unsigned int hashbits)
+{
+ return hash_64(from_kgid(&init_user_ns, acred->gid) |
+ ((u64)from_kuid(&init_user_ns, acred->uid) <<
+ (sizeof(gid_t) * 8)), hashbits);
+}
+
/*
* Lookup generic creds for current process
*/
@@ -258,6 +266,7 @@ generic_key_timeout(struct rpc_auth *auth, struct rpc_cred *cred)
static const struct rpc_authops generic_auth_ops = {
.owner = THIS_MODULE,
.au_name = "Generic",
+ .hash_cred = generic_hash_cred,
.lookup_cred = generic_lookup_cred,
.crcreate = generic_create_cred,
.key_timeout = generic_key_timeout,
--
2.5.5
Add a hash_cred() function for auth_unix, using both the
uid and gid from the auth_cred.
Signed-off-by: Frank Sorenson <[email protected]>
---
net/sunrpc/auth_unix.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index a99278c..4c0c572 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -46,6 +46,14 @@ unx_destroy(struct rpc_auth *auth)
rpcauth_clear_credcache(auth->au_credcache);
}
+static int
+unx_hash_cred(struct auth_cred *acred, unsigned int hashbits)
+{
+ return hash_64(from_kgid(&init_user_ns, acred->gid) |
+ ((u64)from_kuid(&init_user_ns, acred->uid) <<
+ (sizeof(gid_t) * 8)), hashbits);
+}
+
/*
* Lookup AUTH_UNIX creds for current process
*/
@@ -220,6 +228,7 @@ const struct rpc_authops authunix_ops = {
.au_name = "UNIX",
.create = unx_create,
.destroy = unx_destroy,
+ .hash_cred = unx_hash_cred,
.lookup_cred = unx_lookup_cred,
.crcreate = unx_create_cred,
};
--
2.5.5
Replace the generic code to hash the auth_cred with the call to
the auth-specific hash function in the rpc_authops struct.
Signed-off-by: Frank Sorenson <[email protected]>
---
net/sunrpc/auth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index a7e42f9..2bff63a 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -551,7 +551,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
*entry, *new;
unsigned int nr;
- nr = hash_long(from_kuid(&init_user_ns, acred->uid), cache->hashbits);
+ nr = auth->au_ops->hash_cred(acred, cache->hashbits);
rcu_read_lock();
hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) {
--
2.5.5
Add a hash_cred() function for RPCSEC_GSS, using only the
uid from the auth_cred.
Signed-off-by: Frank Sorenson <[email protected]>
---
net/sunrpc/auth_gss/auth_gss.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 976c781..d8bd97a 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1298,6 +1298,12 @@ gss_destroy_cred(struct rpc_cred *cred)
gss_destroy_nullcred(cred);
}
+static int
+gss_hash_cred(struct auth_cred *acred, unsigned int hashbits)
+{
+ return hash_64(from_kuid(&init_user_ns, acred->uid), hashbits);
+}
+
/*
* Lookup RPCSEC_GSS cred for the current process
*/
@@ -1982,6 +1988,7 @@ static const struct rpc_authops authgss_ops = {
.au_name = "RPCSEC_GSS",
.create = gss_create,
.destroy = gss_destroy,
+ .hash_cred = gss_hash_cred,
.lookup_cred = gss_lookup_cred,
.crcreate = gss_create_cred,
.list_pseudoflavors = gss_mech_list_pseudoflavors,
--
2.5.5