The current rpc_cred_cache hashtable uses only the uid in the hash computation. 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 for these uids, while the rest of the hashtable remains nearly empty. This causes very high cpu usage in rpcauth_lookup_credcache, and slow performance for that uid. for (i = 0 ; i < 100000 ; i++) { setregid(-1, i); stat(path, &st); } Add the gid to the hash algorithm to distribute the rpc_creds throughout the cache to avoid long individual hash chains. Signed-off-by: Frank Sorenson <sorenson@xxxxxxxxxx> diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index a7e42f9..2260e58 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -538,6 +538,14 @@ rpcauth_cache_enforce_limit(void) rpcauth_cache_do_shrink(nr_to_scan); } +static unsigned int +rpcauth_hash_acred(struct auth_cred *acred, unsigned int hashbits) +{ + return hash_64(from_kgid(&init_user_ns, acred->gid) | + (from_kuid(&init_user_ns, acred->uid) << (sizeof(gid_t) * 8)), + hashbits); +} + /* * Look up a process' credentials in the authentication cache */ @@ -551,7 +559,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 = rpcauth_hash_acred(acred, cache->hashbits); rcu_read_lock(); hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html