SUNRPC: Add lockless lookup of the server's auth domain
authorTrond Myklebust <trondmy@gmail.com>
Mon, 1 Oct 2018 14:41:44 +0000 (10:41 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 3 Oct 2018 15:32:59 +0000 (11:32 -0400)
Avoid taking the global auth_domain_lock in most lookups of the auth domain
by adding an RCU protected lookup.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
include/linux/sunrpc/svcauth.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c

index 04e404a0788222be04f12f84724a5595f52acfe4..3e53a6e2ada746e1ba7b3eaf2a34b39ad3f46194 100644 (file)
@@ -82,6 +82,7 @@ struct auth_domain {
        struct hlist_node       hash;
        char                    *name;
        struct auth_ops         *flavour;
+       struct rcu_head         rcu_head;
 };
 
 /*
index 860f2a1bbb675d71f4de3bd70acd1284974ffe3a..87c71fb0f0ead16874c8f98f606c737751b4f08e 100644 (file)
@@ -1764,14 +1764,21 @@ out_err:
 }
 
 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);
 
        kfree(dom->name);
        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 = {
        .name           = "rpcsec_gss",
        .owner          = THIS_MODULE,
index f83443856cd128465a3b5be17adeaa1db23132b2..775b8c94265bc329e3a36bf8b3010e53f054c1e2 100644 (file)
@@ -143,10 +143,11 @@ static struct hlist_head  auth_domain_table[DN_HASHMAX];
 static DEFINE_SPINLOCK(auth_domain_lock);
 
 static void auth_domain_release(struct kref *kref)
+       __releases(&auth_domain_lock)
 {
        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);
        spin_unlock(&auth_domain_lock);
 }
@@ -175,7 +176,7 @@ auth_domain_lookup(char *name, struct auth_domain *new)
                }
        }
        if (new)
-               hlist_add_head(&new->hash, head);
+               hlist_add_head_rcu(&new->hash, head);
        spin_unlock(&auth_domain_lock);
        return new;
 }
@@ -183,6 +184,21 @@ EXPORT_SYMBOL_GPL(auth_domain_lookup);
 
 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);
index af7f28fb8102e4313f5ced6aa585e30f3911ca6c..84cf39021a03420ee227d04cf00f9ccbb5a16aae 100644 (file)
@@ -37,20 +37,26 @@ struct unix_domain {
 extern struct auth_ops svcauth_null;
 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);
 
        kfree(dom->name);
        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 *rv;
        struct unix_domain *new = NULL;
 
-       rv = auth_domain_lookup(name, NULL);
+       rv = auth_domain_find(name);
        while(1) {
                if (rv) {
                        if (new && rv != &new->h)