diff options
Diffstat (limited to 'net/sunrpc/auth.c')
-rw-r--r-- | net/sunrpc/auth.c | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f77366717420..383eb919ac0b 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -48,7 +48,7 @@ static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) | |||
48 | 48 | ||
49 | if (!val) | 49 | if (!val) |
50 | goto out_inval; | 50 | goto out_inval; |
51 | ret = strict_strtoul(val, 0, &num); | 51 | ret = kstrtoul(val, 0, &num); |
52 | if (ret == -EINVAL) | 52 | if (ret == -EINVAL) |
53 | goto out_inval; | 53 | goto out_inval; |
54 | nbits = fls(num); | 54 | nbits = fls(num); |
@@ -80,6 +80,10 @@ static struct kernel_param_ops param_ops_hashtbl_sz = { | |||
80 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); | 80 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); |
81 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | 81 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); |
82 | 82 | ||
83 | static unsigned long auth_max_cred_cachesize = ULONG_MAX; | ||
84 | module_param(auth_max_cred_cachesize, ulong, 0644); | ||
85 | MODULE_PARM_DESC(auth_max_cred_cachesize, "RPC credential maximum total cache size"); | ||
86 | |||
83 | static u32 | 87 | static u32 |
84 | pseudoflavor_to_flavor(u32 flavor) { | 88 | pseudoflavor_to_flavor(u32 flavor) { |
85 | if (flavor > RPC_AUTH_MAXFLAVOR) | 89 | if (flavor > RPC_AUTH_MAXFLAVOR) |
@@ -363,6 +367,15 @@ rpcauth_cred_key_to_expire(struct rpc_cred *cred) | |||
363 | } | 367 | } |
364 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); | 368 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); |
365 | 369 | ||
370 | char * | ||
371 | rpcauth_stringify_acceptor(struct rpc_cred *cred) | ||
372 | { | ||
373 | if (!cred->cr_ops->crstringify_acceptor) | ||
374 | return NULL; | ||
375 | return cred->cr_ops->crstringify_acceptor(cred); | ||
376 | } | ||
377 | EXPORT_SYMBOL_GPL(rpcauth_stringify_acceptor); | ||
378 | |||
366 | /* | 379 | /* |
367 | * Destroy a list of credentials | 380 | * Destroy a list of credentials |
368 | */ | 381 | */ |
@@ -472,6 +485,20 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
472 | return freed; | 485 | return freed; |
473 | } | 486 | } |
474 | 487 | ||
488 | static unsigned long | ||
489 | rpcauth_cache_do_shrink(int nr_to_scan) | ||
490 | { | ||
491 | LIST_HEAD(free); | ||
492 | unsigned long freed; | ||
493 | |||
494 | spin_lock(&rpc_credcache_lock); | ||
495 | freed = rpcauth_prune_expired(&free, nr_to_scan); | ||
496 | spin_unlock(&rpc_credcache_lock); | ||
497 | rpcauth_destroy_credlist(&free); | ||
498 | |||
499 | return freed; | ||
500 | } | ||
501 | |||
475 | /* | 502 | /* |
476 | * Run memory cache shrinker. | 503 | * Run memory cache shrinker. |
477 | */ | 504 | */ |
@@ -479,9 +506,6 @@ static unsigned long | |||
479 | rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | 506 | rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) |
480 | 507 | ||
481 | { | 508 | { |
482 | LIST_HEAD(free); | ||
483 | unsigned long freed; | ||
484 | |||
485 | if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) | 509 | if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
486 | return SHRINK_STOP; | 510 | return SHRINK_STOP; |
487 | 511 | ||
@@ -489,12 +513,7 @@ rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | |||
489 | if (list_empty(&cred_unused)) | 513 | if (list_empty(&cred_unused)) |
490 | return SHRINK_STOP; | 514 | return SHRINK_STOP; |
491 | 515 | ||
492 | spin_lock(&rpc_credcache_lock); | 516 | return rpcauth_cache_do_shrink(sc->nr_to_scan); |
493 | freed = rpcauth_prune_expired(&free, sc->nr_to_scan); | ||
494 | spin_unlock(&rpc_credcache_lock); | ||
495 | rpcauth_destroy_credlist(&free); | ||
496 | |||
497 | return freed; | ||
498 | } | 517 | } |
499 | 518 | ||
500 | static unsigned long | 519 | static unsigned long |
@@ -504,6 +523,21 @@ rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) | |||
504 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; | 523 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; |
505 | } | 524 | } |
506 | 525 | ||
526 | static void | ||
527 | rpcauth_cache_enforce_limit(void) | ||
528 | { | ||
529 | unsigned long diff; | ||
530 | unsigned int nr_to_scan; | ||
531 | |||
532 | if (number_cred_unused <= auth_max_cred_cachesize) | ||
533 | return; | ||
534 | diff = number_cred_unused - auth_max_cred_cachesize; | ||
535 | nr_to_scan = 100; | ||
536 | if (diff < nr_to_scan) | ||
537 | nr_to_scan = diff; | ||
538 | rpcauth_cache_do_shrink(nr_to_scan); | ||
539 | } | ||
540 | |||
507 | /* | 541 | /* |
508 | * Look up a process' credentials in the authentication cache | 542 | * Look up a process' credentials in the authentication cache |
509 | */ | 543 | */ |
@@ -523,6 +557,12 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
523 | hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { | 557 | hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { |
524 | if (!entry->cr_ops->crmatch(acred, entry, flags)) | 558 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
525 | continue; | 559 | continue; |
560 | if (flags & RPCAUTH_LOOKUP_RCU) { | ||
561 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) && | ||
562 | !test_bit(RPCAUTH_CRED_NEW, &entry->cr_flags)) | ||
563 | cred = entry; | ||
564 | break; | ||
565 | } | ||
526 | spin_lock(&cache->lock); | 566 | spin_lock(&cache->lock); |
527 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { | 567 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { |
528 | spin_unlock(&cache->lock); | 568 | spin_unlock(&cache->lock); |
@@ -537,6 +577,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
537 | if (cred != NULL) | 577 | if (cred != NULL) |
538 | goto found; | 578 | goto found; |
539 | 579 | ||
580 | if (flags & RPCAUTH_LOOKUP_RCU) | ||
581 | return ERR_PTR(-ECHILD); | ||
582 | |||
540 | new = auth->au_ops->crcreate(auth, acred, flags); | 583 | new = auth->au_ops->crcreate(auth, acred, flags); |
541 | if (IS_ERR(new)) { | 584 | if (IS_ERR(new)) { |
542 | cred = new; | 585 | cred = new; |
@@ -557,6 +600,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
557 | } else | 600 | } else |
558 | list_add_tail(&new->cr_lru, &free); | 601 | list_add_tail(&new->cr_lru, &free); |
559 | spin_unlock(&cache->lock); | 602 | spin_unlock(&cache->lock); |
603 | rpcauth_cache_enforce_limit(); | ||
560 | found: | 604 | found: |
561 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && | 605 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && |
562 | cred->cr_ops->cr_init != NULL && | 606 | cred->cr_ops->cr_init != NULL && |
@@ -586,10 +630,8 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |||
586 | memset(&acred, 0, sizeof(acred)); | 630 | memset(&acred, 0, sizeof(acred)); |
587 | acred.uid = cred->fsuid; | 631 | acred.uid = cred->fsuid; |
588 | acred.gid = cred->fsgid; | 632 | acred.gid = cred->fsgid; |
589 | acred.group_info = get_group_info(((struct cred *)cred)->group_info); | 633 | acred.group_info = cred->group_info; |
590 | |||
591 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 634 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
592 | put_group_info(acred.group_info); | ||
593 | return ret; | 635 | return ret; |
594 | } | 636 | } |
595 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); | 637 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); |