diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-09-27 13:12:44 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-09-30 15:35:17 -0400 |
commit | 4e4c3bef4471c8a06406abd2e3d9493e8478feff (patch) | |
tree | 1d1a2a56b701a76caa61545969f08cdbe2d5af61 | |
parent | 1c6c4b740df12f2162ae5c3fac337137e2776236 (diff) |
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>
-rw-r--r-- | net/sunrpc/auth.c | 128 |
1 files changed, 62 insertions, 66 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 59df5cdba0ac..32985aa515be 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -30,10 +30,9 @@ struct rpc_cred_cache { | |||
30 | 30 | ||
31 | static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; | 31 | static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; |
32 | 32 | ||
33 | static DEFINE_SPINLOCK(rpc_authflavor_lock); | 33 | static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = { |
34 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | 34 | [RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops, |
35 | &authnull_ops, /* AUTH_NULL */ | 35 | [RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops, |
36 | &authunix_ops, /* AUTH_UNIX */ | ||
37 | NULL, /* others can be loadable modules */ | 36 | NULL, /* others can be loadable modules */ |
38 | }; | 37 | }; |
39 | 38 | ||
@@ -93,39 +92,65 @@ pseudoflavor_to_flavor(u32 flavor) { | |||
93 | int | 92 | int |
94 | rpcauth_register(const struct rpc_authops *ops) | 93 | rpcauth_register(const struct rpc_authops *ops) |
95 | { | 94 | { |
95 | const struct rpc_authops *old; | ||
96 | rpc_authflavor_t flavor; | 96 | rpc_authflavor_t flavor; |
97 | int ret = -EPERM; | ||
98 | 97 | ||
99 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | 98 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) |
100 | return -EINVAL; | 99 | return -EINVAL; |
101 | spin_lock(&rpc_authflavor_lock); | 100 | old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], NULL, ops); |
102 | if (auth_flavors[flavor] == NULL) { | 101 | if (old == NULL || old == ops) |
103 | auth_flavors[flavor] = ops; | 102 | return 0; |
104 | ret = 0; | 103 | return -EPERM; |
105 | } | ||
106 | spin_unlock(&rpc_authflavor_lock); | ||
107 | return ret; | ||
108 | } | 104 | } |
109 | EXPORT_SYMBOL_GPL(rpcauth_register); | 105 | EXPORT_SYMBOL_GPL(rpcauth_register); |
110 | 106 | ||
111 | int | 107 | int |
112 | rpcauth_unregister(const struct rpc_authops *ops) | 108 | rpcauth_unregister(const struct rpc_authops *ops) |
113 | { | 109 | { |
110 | const struct rpc_authops *old; | ||
114 | rpc_authflavor_t flavor; | 111 | rpc_authflavor_t flavor; |
115 | int ret = -EPERM; | ||
116 | 112 | ||
117 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | 113 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) |
118 | return -EINVAL; | 114 | return -EINVAL; |
119 | spin_lock(&rpc_authflavor_lock); | 115 | |
120 | if (auth_flavors[flavor] == ops) { | 116 | old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], ops, NULL); |
121 | auth_flavors[flavor] = NULL; | 117 | if (old == ops || old == NULL) |
122 | ret = 0; | 118 | return 0; |
123 | } | 119 | return -EPERM; |
124 | spin_unlock(&rpc_authflavor_lock); | ||
125 | return ret; | ||
126 | } | 120 | } |
127 | EXPORT_SYMBOL_GPL(rpcauth_unregister); | 121 | EXPORT_SYMBOL_GPL(rpcauth_unregister); |
128 | 122 | ||
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 | |||
129 | /** | 154 | /** |
130 | * rpcauth_get_pseudoflavor - check if security flavor is supported | 155 | * rpcauth_get_pseudoflavor - check if security flavor is supported |
131 | * @flavor: a security flavor | 156 | * @flavor: a security flavor |
@@ -138,25 +163,16 @@ EXPORT_SYMBOL_GPL(rpcauth_unregister); | |||
138 | rpc_authflavor_t | 163 | rpc_authflavor_t |
139 | rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) | 164 | rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) |
140 | { | 165 | { |
141 | const struct rpc_authops *ops; | 166 | const struct rpc_authops *ops = rpcauth_get_authops(flavor); |
142 | rpc_authflavor_t pseudoflavor; | 167 | rpc_authflavor_t pseudoflavor; |
143 | 168 | ||
144 | ops = auth_flavors[flavor]; | 169 | if (!ops) |
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); | ||
151 | return RPC_AUTH_MAXFLAVOR; | 170 | return RPC_AUTH_MAXFLAVOR; |
152 | } | ||
153 | spin_unlock(&rpc_authflavor_lock); | ||
154 | |||
155 | pseudoflavor = flavor; | 171 | pseudoflavor = flavor; |
156 | if (ops->info2flavor != NULL) | 172 | if (ops->info2flavor != NULL) |
157 | pseudoflavor = ops->info2flavor(info); | 173 | pseudoflavor = ops->info2flavor(info); |
158 | 174 | ||
159 | module_put(ops->owner); | 175 | rpcauth_put_authops(ops); |
160 | return pseudoflavor; | 176 | return pseudoflavor; |
161 | } | 177 | } |
162 | EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); | 178 | EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); |
@@ -176,25 +192,15 @@ rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info) | |||
176 | const struct rpc_authops *ops; | 192 | const struct rpc_authops *ops; |
177 | int result; | 193 | int result; |
178 | 194 | ||
179 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 195 | ops = rpcauth_get_authops(flavor); |
180 | return -EINVAL; | ||
181 | |||
182 | ops = auth_flavors[flavor]; | ||
183 | if (ops == NULL) | 196 | 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); | ||
189 | return -ENOENT; | 197 | return -ENOENT; |
190 | } | ||
191 | spin_unlock(&rpc_authflavor_lock); | ||
192 | 198 | ||
193 | result = -ENOENT; | 199 | result = -ENOENT; |
194 | if (ops->flavor2info != NULL) | 200 | if (ops->flavor2info != NULL) |
195 | result = ops->flavor2info(pseudoflavor, info); | 201 | result = ops->flavor2info(pseudoflavor, info); |
196 | 202 | ||
197 | module_put(ops->owner); | 203 | rpcauth_put_authops(ops); |
198 | return result; | 204 | return result; |
199 | } | 205 | } |
200 | EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); | 206 | EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); |
@@ -212,15 +218,13 @@ EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); | |||
212 | int | 218 | int |
213 | rpcauth_list_flavors(rpc_authflavor_t *array, int size) | 219 | rpcauth_list_flavors(rpc_authflavor_t *array, int size) |
214 | { | 220 | { |
215 | rpc_authflavor_t flavor; | 221 | const struct rpc_authops *ops; |
216 | int result = 0; | 222 | rpc_authflavor_t flavor, pseudos[4]; |
223 | int i, len, result = 0; | ||
217 | 224 | ||
218 | spin_lock(&rpc_authflavor_lock); | 225 | rcu_read_lock(); |
219 | for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) { | 226 | for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) { |
220 | const struct rpc_authops *ops = auth_flavors[flavor]; | 227 | ops = rcu_dereference(auth_flavors[flavor]); |
221 | rpc_authflavor_t pseudos[4]; | ||
222 | int i, len; | ||
223 | |||
224 | if (result >= size) { | 228 | if (result >= size) { |
225 | result = -ENOMEM; | 229 | result = -ENOMEM; |
226 | break; | 230 | break; |
@@ -245,7 +249,7 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size) | |||
245 | array[result++] = pseudos[i]; | 249 | array[result++] = pseudos[i]; |
246 | } | 250 | } |
247 | } | 251 | } |
248 | spin_unlock(&rpc_authflavor_lock); | 252 | rcu_read_unlock(); |
249 | 253 | ||
250 | dprintk("RPC: %s returns %d\n", __func__, result); | 254 | dprintk("RPC: %s returns %d\n", __func__, result); |
251 | return result; | 255 | return result; |
@@ -255,25 +259,17 @@ EXPORT_SYMBOL_GPL(rpcauth_list_flavors); | |||
255 | struct rpc_auth * | 259 | struct rpc_auth * |
256 | rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 260 | rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
257 | { | 261 | { |
258 | struct rpc_auth *auth; | 262 | struct rpc_auth *auth = ERR_PTR(-EINVAL); |
259 | const struct rpc_authops *ops; | 263 | const struct rpc_authops *ops; |
260 | u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); | 264 | u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); |
261 | 265 | ||
262 | auth = ERR_PTR(-EINVAL); | 266 | ops = rpcauth_get_authops(flavor); |
263 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 267 | if (ops == NULL) |
264 | goto out; | 268 | goto out; |
265 | 269 | ||
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); | ||
275 | auth = ops->create(args, clnt); | 270 | auth = ops->create(args, clnt); |
276 | module_put(ops->owner); | 271 | |
272 | rpcauth_put_authops(ops); | ||
277 | if (IS_ERR(auth)) | 273 | if (IS_ERR(auth)) |
278 | return auth; | 274 | return auth; |
279 | if (clnt->cl_auth) | 275 | if (clnt->cl_auth) |