aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-07-13 21:28:20 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-08-03 17:14:12 -0400
commitbd95608053b7f7813351b0defc0e3e7ef8cf2803 (patch)
treefde08b1ecc2c4aedd30a68244ca502ce5f81f0fe /net/sunrpc
parentd51ac1a8e9b86b2d17d349bb256869cab6522787 (diff)
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>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth.c17
-rw-r--r--net/sunrpc/auth_generic.c6
-rw-r--r--net/sunrpc/auth_null.c2
3 files changed, 23 insertions, 2 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 360decdddc78..24fcbd23ae6c 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -557,6 +557,12 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
557 hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { 557 hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) {
558 if (!entry->cr_ops->crmatch(acred, entry, flags)) 558 if (!entry->cr_ops->crmatch(acred, entry, flags))
559 continue; 559 continue;
560 if (flags & RPCAUTH_LOOKUP_RCU) {
561 if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) &&
562 !test_bit(RPCAUTH_CRED_NEW, &entry->cr_flags))
563 cred = entry;
564 break;
565 }
560 spin_lock(&cache->lock); 566 spin_lock(&cache->lock);
561 if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { 567 if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
562 spin_unlock(&cache->lock); 568 spin_unlock(&cache->lock);
@@ -571,6 +577,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
571 if (cred != NULL) 577 if (cred != NULL)
572 goto found; 578 goto found;
573 579
580 if (flags & RPCAUTH_LOOKUP_RCU)
581 return ERR_PTR(-ECHILD);
582
574 new = auth->au_ops->crcreate(auth, acred, flags); 583 new = auth->au_ops->crcreate(auth, acred, flags);
575 if (IS_ERR(new)) { 584 if (IS_ERR(new)) {
576 cred = new; 585 cred = new;
@@ -621,10 +630,14 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
621 memset(&acred, 0, sizeof(acred)); 630 memset(&acred, 0, sizeof(acred));
622 acred.uid = cred->fsuid; 631 acred.uid = cred->fsuid;
623 acred.gid = cred->fsgid; 632 acred.gid = cred->fsgid;
624 acred.group_info = get_group_info(((struct cred *)cred)->group_info); 633 if (flags & RPCAUTH_LOOKUP_RCU)
634 acred.group_info = rcu_dereference(cred->group_info);
635 else
636 acred.group_info = get_group_info(((struct cred *)cred)->group_info);
625 637
626 ret = auth->au_ops->lookup_cred(auth, &acred, flags); 638 ret = auth->au_ops->lookup_cred(auth, &acred, flags);
627 put_group_info(acred.group_info); 639 if (!(flags & RPCAUTH_LOOKUP_RCU))
640 put_group_info(acred.group_info);
628 return ret; 641 return ret;
629} 642}
630EXPORT_SYMBOL_GPL(rpcauth_lookupcred); 643EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index ed04869b2d4f..6f6b829c9e8e 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -38,6 +38,12 @@ struct rpc_cred *rpc_lookup_cred(void)
38} 38}
39EXPORT_SYMBOL_GPL(rpc_lookup_cred); 39EXPORT_SYMBOL_GPL(rpc_lookup_cred);
40 40
41struct rpc_cred *rpc_lookup_cred_nonblock(void)
42{
43 return rpcauth_lookupcred(&generic_auth, RPCAUTH_LOOKUP_RCU);
44}
45EXPORT_SYMBOL_GPL(rpc_lookup_cred_nonblock);
46
41/* 47/*
42 * Public call interface for looking up machine creds. 48 * Public call interface for looking up machine creds.
43 */ 49 */
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index f0ebe07978a2..712c123e04e9 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -35,6 +35,8 @@ nul_destroy(struct rpc_auth *auth)
35static struct rpc_cred * 35static struct rpc_cred *
36nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 36nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
37{ 37{
38 if (flags & RPCAUTH_LOOKUP_RCU)
39 return &null_cred;
38 return get_rpccred(&null_cred); 40 return get_rpccred(&null_cred);
39} 41}
40 42