diff options
Diffstat (limited to 'net/sunrpc/auth.c')
-rw-r--r-- | net/sunrpc/auth.c | 91 |
1 files changed, 57 insertions, 34 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 00f9649b0901..ad7bde2c437e 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -112,6 +112,14 @@ rpcauth_release(struct rpc_auth *auth) | |||
112 | 112 | ||
113 | static DEFINE_SPINLOCK(rpc_credcache_lock); | 113 | static DEFINE_SPINLOCK(rpc_credcache_lock); |
114 | 114 | ||
115 | static void | ||
116 | rpcauth_unhash_cred_locked(struct rpc_cred *cred) | ||
117 | { | ||
118 | hlist_del_rcu(&cred->cr_hash); | ||
119 | smp_mb__before_clear_bit(); | ||
120 | clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); | ||
121 | } | ||
122 | |||
115 | /* | 123 | /* |
116 | * Initialize RPC credential cache | 124 | * Initialize RPC credential cache |
117 | */ | 125 | */ |
@@ -166,8 +174,7 @@ rpcauth_clear_credcache(struct rpc_cred_cache *cache) | |||
166 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | 174 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); |
167 | get_rpccred(cred); | 175 | get_rpccred(cred); |
168 | list_move_tail(&cred->cr_lru, &free); | 176 | list_move_tail(&cred->cr_lru, &free); |
169 | smp_wmb(); | 177 | rpcauth_unhash_cred_locked(cred); |
170 | hlist_del_init(&cred->cr_hash); | ||
171 | } | 178 | } |
172 | } | 179 | } |
173 | spin_unlock(&rpc_credcache_lock); | 180 | spin_unlock(&rpc_credcache_lock); |
@@ -207,8 +214,7 @@ rpcauth_prune_expired(struct list_head *free) | |||
207 | continue; | 214 | continue; |
208 | get_rpccred(cred); | 215 | get_rpccred(cred); |
209 | list_add_tail(&cred->cr_lru, free); | 216 | list_add_tail(&cred->cr_lru, free); |
210 | smp_wmb(); | 217 | rpcauth_unhash_cred_locked(cred); |
211 | hlist_del_init(&cred->cr_hash); | ||
212 | } | 218 | } |
213 | } | 219 | } |
214 | 220 | ||
@@ -218,10 +224,12 @@ rpcauth_prune_expired(struct list_head *free) | |||
218 | static void | 224 | static void |
219 | rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free) | 225 | rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free) |
220 | { | 226 | { |
221 | if (time_before(jiffies, cache->nextgc)) | 227 | if (list_empty(&cred_unused) || time_before(jiffies, cache->nextgc)) |
222 | return; | 228 | return; |
229 | spin_lock(&rpc_credcache_lock); | ||
223 | cache->nextgc = jiffies + cache->expire; | 230 | cache->nextgc = jiffies + cache->expire; |
224 | rpcauth_prune_expired(free); | 231 | rpcauth_prune_expired(free); |
232 | spin_unlock(&rpc_credcache_lock); | ||
225 | } | 233 | } |
226 | 234 | ||
227 | /* | 235 | /* |
@@ -234,42 +242,57 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
234 | LIST_HEAD(free); | 242 | LIST_HEAD(free); |
235 | struct rpc_cred_cache *cache = auth->au_credcache; | 243 | struct rpc_cred_cache *cache = auth->au_credcache; |
236 | struct hlist_node *pos; | 244 | struct hlist_node *pos; |
237 | struct rpc_cred *new = NULL, | 245 | struct rpc_cred *cred = NULL, |
238 | *cred = NULL, | 246 | *entry, *new; |
239 | *entry; | ||
240 | int nr = 0; | 247 | int nr = 0; |
241 | 248 | ||
242 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) | 249 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) |
243 | nr = acred->uid & RPC_CREDCACHE_MASK; | 250 | nr = acred->uid & RPC_CREDCACHE_MASK; |
244 | retry: | 251 | |
245 | spin_lock(&rpc_credcache_lock); | 252 | rcu_read_lock(); |
246 | hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { | 253 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { |
247 | if (!entry->cr_ops->crmatch(acred, entry, flags)) | 254 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
248 | continue; | 255 | continue; |
256 | spin_lock(&rpc_credcache_lock); | ||
257 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { | ||
258 | spin_unlock(&rpc_credcache_lock); | ||
259 | continue; | ||
260 | } | ||
249 | cred = get_rpccred(entry); | 261 | cred = get_rpccred(entry); |
250 | hlist_del(&entry->cr_hash); | 262 | spin_unlock(&rpc_credcache_lock); |
251 | break; | 263 | break; |
252 | } | 264 | } |
253 | if (new) { | 265 | rcu_read_unlock(); |
254 | if (cred) | 266 | |
255 | list_add_tail(&new->cr_lru, &free); | 267 | if (cred != NULL) { |
256 | else | 268 | rpcauth_gc_credcache(cache, &free); |
257 | cred = new; | 269 | goto found; |
258 | } | ||
259 | if (cred) { | ||
260 | hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); | ||
261 | } | 270 | } |
262 | rpcauth_gc_credcache(cache, &free); | ||
263 | spin_unlock(&rpc_credcache_lock); | ||
264 | 271 | ||
265 | rpcauth_destroy_credlist(&free); | 272 | new = auth->au_ops->crcreate(auth, acred, flags); |
273 | if (IS_ERR(new)) { | ||
274 | cred = new; | ||
275 | goto out; | ||
276 | } | ||
266 | 277 | ||
267 | if (!cred) { | 278 | spin_lock(&rpc_credcache_lock); |
268 | new = auth->au_ops->crcreate(auth, acred, flags); | 279 | hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { |
269 | if (!IS_ERR(new)) | 280 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
270 | goto retry; | 281 | continue; |
282 | cred = get_rpccred(entry); | ||
283 | break; | ||
284 | } | ||
285 | if (cred == NULL) { | ||
271 | cred = new; | 286 | cred = new; |
272 | } else if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) | 287 | set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); |
288 | hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); | ||
289 | } else | ||
290 | list_add_tail(&new->cr_lru, &free); | ||
291 | rpcauth_prune_expired(&free); | ||
292 | cache->nextgc = jiffies + cache->expire; | ||
293 | spin_unlock(&rpc_credcache_lock); | ||
294 | found: | ||
295 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) | ||
273 | && cred->cr_ops->cr_init != NULL | 296 | && cred->cr_ops->cr_init != NULL |
274 | && !(flags & RPCAUTH_LOOKUP_NEW)) { | 297 | && !(flags & RPCAUTH_LOOKUP_NEW)) { |
275 | int res = cred->cr_ops->cr_init(auth, cred); | 298 | int res = cred->cr_ops->cr_init(auth, cred); |
@@ -278,8 +301,9 @@ retry: | |||
278 | cred = ERR_PTR(res); | 301 | cred = ERR_PTR(res); |
279 | } | 302 | } |
280 | } | 303 | } |
281 | 304 | rpcauth_destroy_credlist(&free); | |
282 | return (struct rpc_cred *) cred; | 305 | out: |
306 | return cred; | ||
283 | } | 307 | } |
284 | 308 | ||
285 | struct rpc_cred * | 309 | struct rpc_cred * |
@@ -357,21 +381,20 @@ void | |||
357 | put_rpccred(struct rpc_cred *cred) | 381 | put_rpccred(struct rpc_cred *cred) |
358 | { | 382 | { |
359 | /* Fast path for unhashed credentials */ | 383 | /* Fast path for unhashed credentials */ |
360 | if (!hlist_unhashed(&cred->cr_hash)) | 384 | if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) |
361 | goto need_lock; | 385 | goto need_lock; |
362 | 386 | ||
363 | if (!atomic_dec_and_test(&cred->cr_count)) | 387 | if (!atomic_dec_and_test(&cred->cr_count)) |
364 | return; | 388 | return; |
365 | goto out_destroy; | 389 | goto out_destroy; |
366 | |||
367 | need_lock: | 390 | need_lock: |
368 | if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) | 391 | if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) |
369 | return; | 392 | return; |
370 | if (!list_empty(&cred->cr_lru)) | 393 | if (!list_empty(&cred->cr_lru)) |
371 | list_del_init(&cred->cr_lru); | 394 | list_del_init(&cred->cr_lru); |
372 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | 395 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) |
373 | hlist_del(&cred->cr_hash); | 396 | rpcauth_unhash_cred_locked(cred); |
374 | else if (!hlist_unhashed(&cred->cr_hash)) { | 397 | else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { |
375 | cred->cr_expire = jiffies; | 398 | cred->cr_expire = jiffies; |
376 | list_add_tail(&cred->cr_lru, &cred_unused); | 399 | list_add_tail(&cred->cr_lru, &cred_unused); |
377 | spin_unlock(&rpc_credcache_lock); | 400 | spin_unlock(&rpc_credcache_lock); |