mirror of https://gitee.com/openkylin/linux.git
sunrpc/auth: allow lockless (rcu) lookup of credential cache.
The new flag RPCAUTH_LOOKUP_RCU to credential lookup avoids locking, does not take a reference on the returned credential, and returns -ECHILD if a simple lookup was not possible. The returned value can only be used within an rcu_read_lock protected region. The main user of this is the new rpc_lookup_cred_nonblock() which returns a pointer to the current credential which is only rcu-safe (no ref-count held), and might return -ECHILD if allocation was required. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
parent
d51ac1a8e9
commit
bd95608053
|
@ -103,6 +103,7 @@ struct rpc_auth_create_args {
|
||||||
|
|
||||||
/* Flags for rpcauth_lookupcred() */
|
/* Flags for rpcauth_lookupcred() */
|
||||||
#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
|
#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
|
||||||
|
#define RPCAUTH_LOOKUP_RCU 0x02 /* lock-less lookup */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client authentication ops
|
* Client authentication ops
|
||||||
|
@ -154,6 +155,7 @@ void rpc_destroy_generic_auth(void);
|
||||||
void rpc_destroy_authunix(void);
|
void rpc_destroy_authunix(void);
|
||||||
|
|
||||||
struct rpc_cred * rpc_lookup_cred(void);
|
struct rpc_cred * rpc_lookup_cred(void);
|
||||||
|
struct rpc_cred * rpc_lookup_cred_nonblock(void);
|
||||||
struct rpc_cred * rpc_lookup_machine_cred(const char *service_name);
|
struct rpc_cred * rpc_lookup_machine_cred(const char *service_name);
|
||||||
int rpcauth_register(const struct rpc_authops *);
|
int rpcauth_register(const struct rpc_authops *);
|
||||||
int rpcauth_unregister(const struct rpc_authops *);
|
int rpcauth_unregister(const struct rpc_authops *);
|
||||||
|
|
|
@ -557,6 +557,12 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
|
||||||
hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) {
|
hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) {
|
||||||
if (!entry->cr_ops->crmatch(acred, entry, flags))
|
if (!entry->cr_ops->crmatch(acred, entry, flags))
|
||||||
continue;
|
continue;
|
||||||
|
if (flags & RPCAUTH_LOOKUP_RCU) {
|
||||||
|
if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) &&
|
||||||
|
!test_bit(RPCAUTH_CRED_NEW, &entry->cr_flags))
|
||||||
|
cred = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
spin_lock(&cache->lock);
|
spin_lock(&cache->lock);
|
||||||
if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
|
if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
|
||||||
spin_unlock(&cache->lock);
|
spin_unlock(&cache->lock);
|
||||||
|
@ -571,6 +577,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
|
||||||
if (cred != NULL)
|
if (cred != NULL)
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
|
if (flags & RPCAUTH_LOOKUP_RCU)
|
||||||
|
return ERR_PTR(-ECHILD);
|
||||||
|
|
||||||
new = auth->au_ops->crcreate(auth, acred, flags);
|
new = auth->au_ops->crcreate(auth, acred, flags);
|
||||||
if (IS_ERR(new)) {
|
if (IS_ERR(new)) {
|
||||||
cred = new;
|
cred = new;
|
||||||
|
@ -621,10 +630,14 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
|
||||||
memset(&acred, 0, sizeof(acred));
|
memset(&acred, 0, sizeof(acred));
|
||||||
acred.uid = cred->fsuid;
|
acred.uid = cred->fsuid;
|
||||||
acred.gid = cred->fsgid;
|
acred.gid = cred->fsgid;
|
||||||
acred.group_info = get_group_info(((struct cred *)cred)->group_info);
|
if (flags & RPCAUTH_LOOKUP_RCU)
|
||||||
|
acred.group_info = rcu_dereference(cred->group_info);
|
||||||
|
else
|
||||||
|
acred.group_info = get_group_info(((struct cred *)cred)->group_info);
|
||||||
|
|
||||||
ret = auth->au_ops->lookup_cred(auth, &acred, flags);
|
ret = auth->au_ops->lookup_cred(auth, &acred, flags);
|
||||||
put_group_info(acred.group_info);
|
if (!(flags & RPCAUTH_LOOKUP_RCU))
|
||||||
|
put_group_info(acred.group_info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
|
EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
|
||||||
|
|
|
@ -38,6 +38,12 @@ struct rpc_cred *rpc_lookup_cred(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpc_lookup_cred);
|
EXPORT_SYMBOL_GPL(rpc_lookup_cred);
|
||||||
|
|
||||||
|
struct rpc_cred *rpc_lookup_cred_nonblock(void)
|
||||||
|
{
|
||||||
|
return rpcauth_lookupcred(&generic_auth, RPCAUTH_LOOKUP_RCU);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rpc_lookup_cred_nonblock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public call interface for looking up machine creds.
|
* Public call interface for looking up machine creds.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,8 @@ nul_destroy(struct rpc_auth *auth)
|
||||||
static struct rpc_cred *
|
static struct rpc_cred *
|
||||||
nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
|
nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
|
||||||
{
|
{
|
||||||
|
if (flags & RPCAUTH_LOOKUP_RCU)
|
||||||
|
return &null_cred;
|
||||||
return get_rpccred(&null_cred);
|
return get_rpccred(&null_cred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue