summaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2018-10-11 16:11:09 -0400
committerTrond Myklebust <trond.myklebust@hammerspace.com>2018-10-23 12:24:33 -0400
commit95cd623250adce2269e71cfeaf1d487cf4b0d088 (patch)
treeb37ee08f9ed1d56df5f57a17ede97e36dda36f8b /net/sunrpc/auth.c
parent86bbd7422ae6a33735df6846fd685e46686da714 (diff)
SUNRPC: Clean up the AUTH cache code
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Diffstat (limited to 'net/sunrpc/auth.c')
-rw-r--r--net/sunrpc/auth.c147
1 files changed, 86 insertions, 61 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 32985aa515be..c1576b110974 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -291,25 +291,30 @@ rpcauth_release(struct rpc_auth *auth)
291 291
292static DEFINE_SPINLOCK(rpc_credcache_lock); 292static DEFINE_SPINLOCK(rpc_credcache_lock);
293 293
294static void 294/*
295 * On success, the caller is responsible for freeing the reference
296 * held by the hashtable
297 */
298static bool
295rpcauth_unhash_cred_locked(struct rpc_cred *cred) 299rpcauth_unhash_cred_locked(struct rpc_cred *cred)
296{ 300{
301 if (!test_and_clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))
302 return false;
297 hlist_del_rcu(&cred->cr_hash); 303 hlist_del_rcu(&cred->cr_hash);
298 smp_mb__before_atomic(); 304 return true;
299 clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
300} 305}
301 306
302static int 307static bool
303rpcauth_unhash_cred(struct rpc_cred *cred) 308rpcauth_unhash_cred(struct rpc_cred *cred)
304{ 309{
305 spinlock_t *cache_lock; 310 spinlock_t *cache_lock;
306 int ret; 311 bool ret;
307 312
313 if (!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))
314 return false;
308 cache_lock = &cred->cr_auth->au_credcache->lock; 315 cache_lock = &cred->cr_auth->au_credcache->lock;
309 spin_lock(cache_lock); 316 spin_lock(cache_lock);
310 ret = atomic_read(&cred->cr_count) == 0; 317 ret = rpcauth_unhash_cred_locked(cred);
311 if (ret)
312 rpcauth_unhash_cred_locked(cred);
313 spin_unlock(cache_lock); 318 spin_unlock(cache_lock);
314 return ret; 319 return ret;
315} 320}
@@ -388,6 +393,44 @@ void rpcauth_destroy_credlist(struct list_head *head)
388 } 393 }
389} 394}
390 395
396static void
397rpcauth_lru_add_locked(struct rpc_cred *cred)
398{
399 if (!list_empty(&cred->cr_lru))
400 return;
401 number_cred_unused++;
402 list_add_tail(&cred->cr_lru, &cred_unused);
403}
404
405static void
406rpcauth_lru_add(struct rpc_cred *cred)
407{
408 if (!list_empty(&cred->cr_lru))
409 return;
410 spin_lock(&rpc_credcache_lock);
411 rpcauth_lru_add_locked(cred);
412 spin_unlock(&rpc_credcache_lock);
413}
414
415static void
416rpcauth_lru_remove_locked(struct rpc_cred *cred)
417{
418 if (list_empty(&cred->cr_lru))
419 return;
420 number_cred_unused--;
421 list_del_init(&cred->cr_lru);
422}
423
424static void
425rpcauth_lru_remove(struct rpc_cred *cred)
426{
427 if (list_empty(&cred->cr_lru))
428 return;
429 spin_lock(&rpc_credcache_lock);
430 rpcauth_lru_remove_locked(cred);
431 spin_unlock(&rpc_credcache_lock);
432}
433
391/* 434/*
392 * Clear the RPC credential cache, and delete those credentials 435 * Clear the RPC credential cache, and delete those credentials
393 * that are not referenced. 436 * that are not referenced.
@@ -407,13 +450,10 @@ rpcauth_clear_credcache(struct rpc_cred_cache *cache)
407 head = &cache->hashtable[i]; 450 head = &cache->hashtable[i];
408 while (!hlist_empty(head)) { 451 while (!hlist_empty(head)) {
409 cred = hlist_entry(head->first, struct rpc_cred, cr_hash); 452 cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
410 get_rpccred(cred);
411 if (!list_empty(&cred->cr_lru)) {
412 list_del(&cred->cr_lru);
413 number_cred_unused--;
414 }
415 list_add_tail(&cred->cr_lru, &free);
416 rpcauth_unhash_cred_locked(cred); 453 rpcauth_unhash_cred_locked(cred);
454 /* Note: We now hold a reference to cred */
455 rpcauth_lru_remove_locked(cred);
456 list_add_tail(&cred->cr_lru, &free);
417 } 457 }
418 } 458 }
419 spin_unlock(&cache->lock); 459 spin_unlock(&cache->lock);
@@ -447,7 +487,6 @@ EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache);
447static long 487static long
448rpcauth_prune_expired(struct list_head *free, int nr_to_scan) 488rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
449{ 489{
450 spinlock_t *cache_lock;
451 struct rpc_cred *cred, *next; 490 struct rpc_cred *cred, *next;
452 unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM; 491 unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM;
453 long freed = 0; 492 long freed = 0;
@@ -456,32 +495,24 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
456 495
457 if (nr_to_scan-- == 0) 496 if (nr_to_scan-- == 0)
458 break; 497 break;
498 if (atomic_read(&cred->cr_count) > 1) {
499 rpcauth_lru_remove_locked(cred);
500 continue;
501 }
459 /* 502 /*
460 * Enforce a 60 second garbage collection moratorium 503 * Enforce a 60 second garbage collection moratorium
461 * Note that the cred_unused list must be time-ordered. 504 * Note that the cred_unused list must be time-ordered.
462 */ 505 */
463 if (time_in_range(cred->cr_expire, expired, jiffies) && 506 if (!time_in_range(cred->cr_expire, expired, jiffies))
464 test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { 507 continue;
465 freed = SHRINK_STOP; 508 if (!rpcauth_unhash_cred(cred))
466 break;
467 }
468
469 list_del_init(&cred->cr_lru);
470 number_cred_unused--;
471 freed++;
472 if (atomic_read(&cred->cr_count) != 0)
473 continue; 509 continue;
474 510
475 cache_lock = &cred->cr_auth->au_credcache->lock; 511 rpcauth_lru_remove_locked(cred);
476 spin_lock(cache_lock); 512 freed++;
477 if (atomic_read(&cred->cr_count) == 0) { 513 list_add_tail(&cred->cr_lru, free);
478 get_rpccred(cred);
479 list_add_tail(&cred->cr_lru, free);
480 rpcauth_unhash_cred_locked(cred);
481 }
482 spin_unlock(cache_lock);
483 } 514 }
484 return freed; 515 return freed ? freed : SHRINK_STOP;
485} 516}
486 517
487static unsigned long 518static unsigned long
@@ -595,6 +626,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
595 if (cred == NULL) { 626 if (cred == NULL) {
596 cred = new; 627 cred = new;
597 set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 628 set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
629 atomic_inc(&cred->cr_count);
598 hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); 630 hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
599 } else 631 } else
600 list_add_tail(&new->cr_lru, &free); 632 list_add_tail(&new->cr_lru, &free);
@@ -709,36 +741,29 @@ put_rpccred(struct rpc_cred *cred)
709{ 741{
710 if (cred == NULL) 742 if (cred == NULL)
711 return; 743 return;
712 /* Fast path for unhashed credentials */ 744 rcu_read_lock();
713 if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) == 0) { 745 if (atomic_dec_and_test(&cred->cr_count))
746 goto destroy;
747 if (atomic_read(&cred->cr_count) != 1 ||
748 !test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags))
749 goto out;
750 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
751 cred->cr_expire = jiffies;
752 rpcauth_lru_add(cred);
753 /* Race breaker */
754 if (unlikely(!test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags)))
755 rpcauth_lru_remove(cred);
756 } else if (rpcauth_unhash_cred(cred)) {
757 rpcauth_lru_remove(cred);
714 if (atomic_dec_and_test(&cred->cr_count)) 758 if (atomic_dec_and_test(&cred->cr_count))
715 cred->cr_ops->crdestroy(cred); 759 goto destroy;
716 return;
717 }
718
719 if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
720 return;
721 if (!list_empty(&cred->cr_lru)) {
722 number_cred_unused--;
723 list_del_init(&cred->cr_lru);
724 }
725 if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
726 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
727 cred->cr_expire = jiffies;
728 list_add_tail(&cred->cr_lru, &cred_unused);
729 number_cred_unused++;
730 goto out_nodestroy;
731 }
732 if (!rpcauth_unhash_cred(cred)) {
733 /* We were hashed and someone looked us up... */
734 goto out_nodestroy;
735 }
736 } 760 }
737 spin_unlock(&rpc_credcache_lock); 761out:
738 cred->cr_ops->crdestroy(cred); 762 rcu_read_unlock();
739 return; 763 return;
740out_nodestroy: 764destroy:
741 spin_unlock(&rpc_credcache_lock); 765 rcu_read_unlock();
766 cred->cr_ops->crdestroy(cred);
742} 767}
743EXPORT_SYMBOL_GPL(put_rpccred); 768EXPORT_SYMBOL_GPL(put_rpccred);
744 769