diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-10-11 16:11:09 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-10-23 12:24:33 -0400 |
commit | 95cd623250adce2269e71cfeaf1d487cf4b0d088 (patch) | |
tree | b37ee08f9ed1d56df5f57a17ede97e36dda36f8b /net/sunrpc/auth.c | |
parent | 86bbd7422ae6a33735df6846fd685e46686da714 (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.c | 147 |
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 | ||
292 | static DEFINE_SPINLOCK(rpc_credcache_lock); | 292 | static DEFINE_SPINLOCK(rpc_credcache_lock); |
293 | 293 | ||
294 | static void | 294 | /* |
295 | * On success, the caller is responsible for freeing the reference | ||
296 | * held by the hashtable | ||
297 | */ | ||
298 | static bool | ||
295 | rpcauth_unhash_cred_locked(struct rpc_cred *cred) | 299 | rpcauth_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 | ||
302 | static int | 307 | static bool |
303 | rpcauth_unhash_cred(struct rpc_cred *cred) | 308 | rpcauth_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 | ||
396 | static void | ||
397 | rpcauth_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 | |||
405 | static void | ||
406 | rpcauth_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 | |||
415 | static void | ||
416 | rpcauth_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 | |||
424 | static void | ||
425 | rpcauth_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); | |||
447 | static long | 487 | static long |
448 | rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | 488 | rpcauth_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 | ||
487 | static unsigned long | 518 | static 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); | 761 | out: |
738 | cred->cr_ops->crdestroy(cred); | 762 | rcu_read_unlock(); |
739 | return; | 763 | return; |
740 | out_nodestroy: | 764 | destroy: |
741 | spin_unlock(&rpc_credcache_lock); | 765 | rcu_read_unlock(); |
766 | cred->cr_ops->crdestroy(cred); | ||
742 | } | 767 | } |
743 | EXPORT_SYMBOL_GPL(put_rpccred); | 768 | EXPORT_SYMBOL_GPL(put_rpccred); |
744 | 769 | ||