Skip to content

Commit 4e4c3be

Browse files
author
Trond Myklebust
committed
SUNRPC: Remove rpc_authflavor_lock in favour of RCU locking
Module removal is RCU safe by design, so we really have no need to lock the auth_flavors[] array. Substitute a lockless scheme to add/remove entries in the array, and then use rcu. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 1c6c4b7 commit 4e4c3be

File tree

1 file changed

+62
-66
lines changed

1 file changed

+62
-66
lines changed

net/sunrpc/auth.c

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@ struct rpc_cred_cache {
3030

3131
static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS;
3232

33-
static DEFINE_SPINLOCK(rpc_authflavor_lock);
34-
static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
35-
&authnull_ops, /* AUTH_NULL */
36-
&authunix_ops, /* AUTH_UNIX */
33+
static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
34+
[RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops,
35+
[RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops,
3736
NULL, /* others can be loadable modules */
3837
};
3938

@@ -93,39 +92,65 @@ pseudoflavor_to_flavor(u32 flavor) {
9392
int
9493
rpcauth_register(const struct rpc_authops *ops)
9594
{
95+
const struct rpc_authops *old;
9696
rpc_authflavor_t flavor;
97-
int ret = -EPERM;
9897

9998
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
10099
return -EINVAL;
101-
spin_lock(&rpc_authflavor_lock);
102-
if (auth_flavors[flavor] == NULL) {
103-
auth_flavors[flavor] = ops;
104-
ret = 0;
105-
}
106-
spin_unlock(&rpc_authflavor_lock);
107-
return ret;
100+
old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], NULL, ops);
101+
if (old == NULL || old == ops)
102+
return 0;
103+
return -EPERM;
108104
}
109105
EXPORT_SYMBOL_GPL(rpcauth_register);
110106

111107
int
112108
rpcauth_unregister(const struct rpc_authops *ops)
113109
{
110+
const struct rpc_authops *old;
114111
rpc_authflavor_t flavor;
115-
int ret = -EPERM;
116112

117113
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
118114
return -EINVAL;
119-
spin_lock(&rpc_authflavor_lock);
120-
if (auth_flavors[flavor] == ops) {
121-
auth_flavors[flavor] = NULL;
122-
ret = 0;
123-
}
124-
spin_unlock(&rpc_authflavor_lock);
125-
return ret;
115+
116+
old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], ops, NULL);
117+
if (old == ops || old == NULL)
118+
return 0;
119+
return -EPERM;
126120
}
127121
EXPORT_SYMBOL_GPL(rpcauth_unregister);
128122

123+
static const struct rpc_authops *
124+
rpcauth_get_authops(rpc_authflavor_t flavor)
125+
{
126+
const struct rpc_authops *ops;
127+
128+
if (flavor >= RPC_AUTH_MAXFLAVOR)
129+
return NULL;
130+
131+
rcu_read_lock();
132+
ops = rcu_dereference(auth_flavors[flavor]);
133+
if (ops == NULL) {
134+
rcu_read_unlock();
135+
request_module("rpc-auth-%u", flavor);
136+
rcu_read_lock();
137+
ops = rcu_dereference(auth_flavors[flavor]);
138+
if (ops == NULL)
139+
goto out;
140+
}
141+
if (!try_module_get(ops->owner))
142+
ops = NULL;
143+
out:
144+
rcu_read_unlock();
145+
return ops;
146+
}
147+
148+
static void
149+
rpcauth_put_authops(const struct rpc_authops *ops)
150+
{
151+
module_put(ops->owner);
152+
}
153+
129154
/**
130155
* rpcauth_get_pseudoflavor - check if security flavor is supported
131156
* @flavor: a security flavor
@@ -138,25 +163,16 @@ EXPORT_SYMBOL_GPL(rpcauth_unregister);
138163
rpc_authflavor_t
139164
rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
140165
{
141-
const struct rpc_authops *ops;
166+
const struct rpc_authops *ops = rpcauth_get_authops(flavor);
142167
rpc_authflavor_t pseudoflavor;
143168

144-
ops = auth_flavors[flavor];
145-
if (ops == NULL)
146-
request_module("rpc-auth-%u", flavor);
147-
spin_lock(&rpc_authflavor_lock);
148-
ops = auth_flavors[flavor];
149-
if (ops == NULL || !try_module_get(ops->owner)) {
150-
spin_unlock(&rpc_authflavor_lock);
169+
if (!ops)
151170
return RPC_AUTH_MAXFLAVOR;
152-
}
153-
spin_unlock(&rpc_authflavor_lock);
154-
155171
pseudoflavor = flavor;
156172
if (ops->info2flavor != NULL)
157173
pseudoflavor = ops->info2flavor(info);
158174

159-
module_put(ops->owner);
175+
rpcauth_put_authops(ops);
160176
return pseudoflavor;
161177
}
162178
EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
@@ -176,25 +192,15 @@ rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
176192
const struct rpc_authops *ops;
177193
int result;
178194

179-
if (flavor >= RPC_AUTH_MAXFLAVOR)
180-
return -EINVAL;
181-
182-
ops = auth_flavors[flavor];
195+
ops = rpcauth_get_authops(flavor);
183196
if (ops == NULL)
184-
request_module("rpc-auth-%u", flavor);
185-
spin_lock(&rpc_authflavor_lock);
186-
ops = auth_flavors[flavor];
187-
if (ops == NULL || !try_module_get(ops->owner)) {
188-
spin_unlock(&rpc_authflavor_lock);
189197
return -ENOENT;
190-
}
191-
spin_unlock(&rpc_authflavor_lock);
192198

193199
result = -ENOENT;
194200
if (ops->flavor2info != NULL)
195201
result = ops->flavor2info(pseudoflavor, info);
196202

197-
module_put(ops->owner);
203+
rpcauth_put_authops(ops);
198204
return result;
199205
}
200206
EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
@@ -212,15 +218,13 @@ EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
212218
int
213219
rpcauth_list_flavors(rpc_authflavor_t *array, int size)
214220
{
215-
rpc_authflavor_t flavor;
216-
int result = 0;
221+
const struct rpc_authops *ops;
222+
rpc_authflavor_t flavor, pseudos[4];
223+
int i, len, result = 0;
217224

218-
spin_lock(&rpc_authflavor_lock);
225+
rcu_read_lock();
219226
for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) {
220-
const struct rpc_authops *ops = auth_flavors[flavor];
221-
rpc_authflavor_t pseudos[4];
222-
int i, len;
223-
227+
ops = rcu_dereference(auth_flavors[flavor]);
224228
if (result >= size) {
225229
result = -ENOMEM;
226230
break;
@@ -245,7 +249,7 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size)
245249
array[result++] = pseudos[i];
246250
}
247251
}
248-
spin_unlock(&rpc_authflavor_lock);
252+
rcu_read_unlock();
249253

250254
dprintk("RPC: %s returns %d\n", __func__, result);
251255
return result;
@@ -255,25 +259,17 @@ EXPORT_SYMBOL_GPL(rpcauth_list_flavors);
255259
struct rpc_auth *
256260
rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
257261
{
258-
struct rpc_auth *auth;
262+
struct rpc_auth *auth = ERR_PTR(-EINVAL);
259263
const struct rpc_authops *ops;
260-
u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor);
264+
u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor);
261265

262-
auth = ERR_PTR(-EINVAL);
263-
if (flavor >= RPC_AUTH_MAXFLAVOR)
266+
ops = rpcauth_get_authops(flavor);
267+
if (ops == NULL)
264268
goto out;
265269

266-
if ((ops = auth_flavors[flavor]) == NULL)
267-
request_module("rpc-auth-%u", flavor);
268-
spin_lock(&rpc_authflavor_lock);
269-
ops = auth_flavors[flavor];
270-
if (ops == NULL || !try_module_get(ops->owner)) {
271-
spin_unlock(&rpc_authflavor_lock);
272-
goto out;
273-
}
274-
spin_unlock(&rpc_authflavor_lock);
275270
auth = ops->create(args, clnt);
276-
module_put(ops->owner);
271+
272+
rpcauth_put_authops(ops);
277273
if (IS_ERR(auth))
278274
return auth;
279275
if (clnt->cl_auth)

0 commit comments

Comments
 (0)