Commit 608a0ab2 authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields

SUNRPC: Add lockless lookup of the server's auth domain

Avoid taking the global auth_domain_lock in most lookups of the auth domain
by adding an RCU protected lookup.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 30382d6c
...@@ -82,6 +82,7 @@ struct auth_domain { ...@@ -82,6 +82,7 @@ struct auth_domain {
struct hlist_node hash; struct hlist_node hash;
char *name; char *name;
struct auth_ops *flavour; struct auth_ops *flavour;
struct rcu_head rcu_head;
}; };
/* /*
......
...@@ -1764,14 +1764,21 @@ svcauth_gss_release(struct svc_rqst *rqstp) ...@@ -1764,14 +1764,21 @@ svcauth_gss_release(struct svc_rqst *rqstp)
} }
static void static void
svcauth_gss_domain_release(struct auth_domain *dom) svcauth_gss_domain_release_rcu(struct rcu_head *head)
{ {
struct auth_domain *dom = container_of(head, struct auth_domain, rcu_head);
struct gss_domain *gd = container_of(dom, struct gss_domain, h); struct gss_domain *gd = container_of(dom, struct gss_domain, h);
kfree(dom->name); kfree(dom->name);
kfree(gd); kfree(gd);
} }
static void
svcauth_gss_domain_release(struct auth_domain *dom)
{
call_rcu(&dom->rcu_head, svcauth_gss_domain_release_rcu);
}
static struct auth_ops svcauthops_gss = { static struct auth_ops svcauthops_gss = {
.name = "rpcsec_gss", .name = "rpcsec_gss",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -143,10 +143,11 @@ static struct hlist_head auth_domain_table[DN_HASHMAX]; ...@@ -143,10 +143,11 @@ static struct hlist_head auth_domain_table[DN_HASHMAX];
static DEFINE_SPINLOCK(auth_domain_lock); static DEFINE_SPINLOCK(auth_domain_lock);
static void auth_domain_release(struct kref *kref) static void auth_domain_release(struct kref *kref)
__releases(&auth_domain_lock)
{ {
struct auth_domain *dom = container_of(kref, struct auth_domain, ref); struct auth_domain *dom = container_of(kref, struct auth_domain, ref);
hlist_del(&dom->hash); hlist_del_rcu(&dom->hash);
dom->flavour->domain_release(dom); dom->flavour->domain_release(dom);
spin_unlock(&auth_domain_lock); spin_unlock(&auth_domain_lock);
} }
...@@ -175,7 +176,7 @@ auth_domain_lookup(char *name, struct auth_domain *new) ...@@ -175,7 +176,7 @@ auth_domain_lookup(char *name, struct auth_domain *new)
} }
} }
if (new) if (new)
hlist_add_head(&new->hash, head); hlist_add_head_rcu(&new->hash, head);
spin_unlock(&auth_domain_lock); spin_unlock(&auth_domain_lock);
return new; return new;
} }
...@@ -183,6 +184,21 @@ EXPORT_SYMBOL_GPL(auth_domain_lookup); ...@@ -183,6 +184,21 @@ EXPORT_SYMBOL_GPL(auth_domain_lookup);
struct auth_domain *auth_domain_find(char *name) struct auth_domain *auth_domain_find(char *name)
{ {
return auth_domain_lookup(name, NULL); struct auth_domain *hp;
struct hlist_head *head;
head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
rcu_read_lock();
hlist_for_each_entry_rcu(hp, head, hash) {
if (strcmp(hp->name, name)==0) {
if (!kref_get_unless_zero(&hp->ref))
hp = NULL;
rcu_read_unlock();
return hp;
}
}
rcu_read_unlock();
return NULL;
} }
EXPORT_SYMBOL_GPL(auth_domain_find); EXPORT_SYMBOL_GPL(auth_domain_find);
...@@ -37,20 +37,26 @@ struct unix_domain { ...@@ -37,20 +37,26 @@ struct unix_domain {
extern struct auth_ops svcauth_null; extern struct auth_ops svcauth_null;
extern struct auth_ops svcauth_unix; extern struct auth_ops svcauth_unix;
static void svcauth_unix_domain_release(struct auth_domain *dom) static void svcauth_unix_domain_release_rcu(struct rcu_head *head)
{ {
struct auth_domain *dom = container_of(head, struct auth_domain, rcu_head);
struct unix_domain *ud = container_of(dom, struct unix_domain, h); struct unix_domain *ud = container_of(dom, struct unix_domain, h);
kfree(dom->name); kfree(dom->name);
kfree(ud); kfree(ud);
} }
static void svcauth_unix_domain_release(struct auth_domain *dom)
{
call_rcu(&dom->rcu_head, svcauth_unix_domain_release_rcu);
}
struct auth_domain *unix_domain_find(char *name) struct auth_domain *unix_domain_find(char *name)
{ {
struct auth_domain *rv; struct auth_domain *rv;
struct unix_domain *new = NULL; struct unix_domain *new = NULL;
rv = auth_domain_lookup(name, NULL); rv = auth_domain_find(name);
while(1) { while(1) {
if (rv) { if (rv) {
if (new && rv != &new->h) if (new && rv != &new->h)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment