hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/net/sunrpc/svcauth.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/net/sunrpc/svcauth.c
34 *
....@@ -18,6 +19,10 @@
1819 #include <linux/err.h>
1920 #include <linux/hash.h>
2021
22
+#include <trace/events/sunrpc.h>
23
+
24
+#include "sunrpc.h"
25
+
2126 #define RPCDBG_FACILITY RPCDBG_AUTH
2227
2328
....@@ -27,11 +32,31 @@
2732 extern struct auth_ops svcauth_null;
2833 extern struct auth_ops svcauth_unix;
2934
30
-static DEFINE_SPINLOCK(authtab_lock);
31
-static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = {
32
- [0] = &svcauth_null,
33
- [1] = &svcauth_unix,
35
+static struct auth_ops __rcu *authtab[RPC_AUTH_MAXFLAVOR] = {
36
+ [RPC_AUTH_NULL] = (struct auth_ops __force __rcu *)&svcauth_null,
37
+ [RPC_AUTH_UNIX] = (struct auth_ops __force __rcu *)&svcauth_unix,
3438 };
39
+
40
+static struct auth_ops *
41
+svc_get_auth_ops(rpc_authflavor_t flavor)
42
+{
43
+ struct auth_ops *aops;
44
+
45
+ if (flavor >= RPC_AUTH_MAXFLAVOR)
46
+ return NULL;
47
+ rcu_read_lock();
48
+ aops = rcu_dereference(authtab[flavor]);
49
+ if (aops != NULL && !try_module_get(aops->owner))
50
+ aops = NULL;
51
+ rcu_read_unlock();
52
+ return aops;
53
+}
54
+
55
+static void
56
+svc_put_auth_ops(struct auth_ops *aops)
57
+{
58
+ module_put(aops->owner);
59
+}
3560
3661 int
3762 svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
....@@ -45,14 +70,11 @@
4570
4671 dprintk("svc: svc_authenticate (%d)\n", flavor);
4772
48
- spin_lock(&authtab_lock);
49
- if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor]) ||
50
- !try_module_get(aops->owner)) {
51
- spin_unlock(&authtab_lock);
73
+ aops = svc_get_auth_ops(flavor);
74
+ if (aops == NULL) {
5275 *authp = rpc_autherr_badcred;
5376 return SVC_DENIED;
5477 }
55
- spin_unlock(&authtab_lock);
5678
5779 rqstp->rq_auth_slack = 0;
5880 init_svc_cred(&rqstp->rq_cred);
....@@ -82,7 +104,7 @@
82104
83105 if (aops) {
84106 rv = aops->release(rqstp);
85
- module_put(aops->owner);
107
+ svc_put_auth_ops(aops);
86108 }
87109 return rv;
88110 }
....@@ -90,13 +112,14 @@
90112 int
91113 svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
92114 {
115
+ struct auth_ops *old;
93116 int rv = -EINVAL;
94
- spin_lock(&authtab_lock);
95
- if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
96
- authtab[flavor] = aops;
97
- rv = 0;
117
+
118
+ if (flavor < RPC_AUTH_MAXFLAVOR) {
119
+ old = cmpxchg((struct auth_ops ** __force)&authtab[flavor], NULL, aops);
120
+ if (old == NULL || old == aops)
121
+ rv = 0;
98122 }
99
- spin_unlock(&authtab_lock);
100123 return rv;
101124 }
102125 EXPORT_SYMBOL_GPL(svc_auth_register);
....@@ -104,10 +127,8 @@
104127 void
105128 svc_auth_unregister(rpc_authflavor_t flavor)
106129 {
107
- spin_lock(&authtab_lock);
108130 if (flavor < RPC_AUTH_MAXFLAVOR)
109
- authtab[flavor] = NULL;
110
- spin_unlock(&authtab_lock);
131
+ rcu_assign_pointer(authtab[flavor], NULL);
111132 }
112133 EXPORT_SYMBOL_GPL(svc_auth_unregister);
113134
....@@ -127,10 +148,11 @@
127148 static DEFINE_SPINLOCK(auth_domain_lock);
128149
129150 static void auth_domain_release(struct kref *kref)
151
+ __releases(&auth_domain_lock)
130152 {
131153 struct auth_domain *dom = container_of(kref, struct auth_domain, ref);
132154
133
- hlist_del(&dom->hash);
155
+ hlist_del_rcu(&dom->hash);
134156 dom->flavour->domain_release(dom);
135157 spin_unlock(&auth_domain_lock);
136158 }
....@@ -159,7 +181,7 @@
159181 }
160182 }
161183 if (new)
162
- hlist_add_head(&new->hash, head);
184
+ hlist_add_head_rcu(&new->hash, head);
163185 spin_unlock(&auth_domain_lock);
164186 return new;
165187 }
....@@ -167,6 +189,44 @@
167189
168190 struct auth_domain *auth_domain_find(char *name)
169191 {
170
- return auth_domain_lookup(name, NULL);
192
+ struct auth_domain *hp;
193
+ struct hlist_head *head;
194
+
195
+ head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
196
+
197
+ rcu_read_lock();
198
+ hlist_for_each_entry_rcu(hp, head, hash) {
199
+ if (strcmp(hp->name, name)==0) {
200
+ if (!kref_get_unless_zero(&hp->ref))
201
+ hp = NULL;
202
+ rcu_read_unlock();
203
+ return hp;
204
+ }
205
+ }
206
+ rcu_read_unlock();
207
+ return NULL;
171208 }
172209 EXPORT_SYMBOL_GPL(auth_domain_find);
210
+
211
+/**
212
+ * auth_domain_cleanup - check that the auth_domain table is empty
213
+ *
214
+ * On module unload the auth_domain_table must be empty. To make it
215
+ * easier to catch bugs which don't clean up domains properly, we
216
+ * warn if anything remains in the table at cleanup time.
217
+ *
218
+ * Note that we cannot proactively remove the domains at this stage.
219
+ * The ->release() function might be in a module that has already been
220
+ * unloaded.
221
+ */
222
+
223
+void auth_domain_cleanup(void)
224
+{
225
+ int h;
226
+ struct auth_domain *hp;
227
+
228
+ for (h = 0; h < DN_HASHMAX; h++)
229
+ hlist_for_each_entry(hp, &auth_domain_table[h], hash)
230
+ pr_warn("svc: domain %s still present at module unload.\n",
231
+ hp->name);
232
+}