diff options
Diffstat (limited to 'net/sunrpc/auth.c')
| -rw-r--r-- | net/sunrpc/auth.c | 39 | 
1 files changed, 23 insertions, 16 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 54a4e042f10..7ee6f7eaddf 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -123,16 +123,19 @@ rpcauth_unhash_cred_locked(struct rpc_cred *cred)  	clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);  } -static void +static int  rpcauth_unhash_cred(struct rpc_cred *cred)  {  	spinlock_t *cache_lock; +	int ret;  	cache_lock = &cred->cr_auth->au_credcache->lock;  	spin_lock(cache_lock); -	if (atomic_read(&cred->cr_count) == 0) +	ret = atomic_read(&cred->cr_count) == 0; +	if (ret)  		rpcauth_unhash_cred_locked(cred);  	spin_unlock(cache_lock); +	return ret;  }  /* @@ -446,31 +449,35 @@ void  put_rpccred(struct rpc_cred *cred)  {  	/* Fast path for unhashed credentials */ -	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) -		goto need_lock; - -	if (!atomic_dec_and_test(&cred->cr_count)) +	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) == 0) { +		if (atomic_dec_and_test(&cred->cr_count)) +			cred->cr_ops->crdestroy(cred);  		return; -	goto out_destroy; -need_lock: +	} +  	if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))  		return;  	if (!list_empty(&cred->cr_lru)) {  		number_cred_unused--;  		list_del_init(&cred->cr_lru);  	} -	if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) -		rpcauth_unhash_cred(cred);  	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { -		cred->cr_expire = jiffies; -		list_add_tail(&cred->cr_lru, &cred_unused); -		number_cred_unused++; -		spin_unlock(&rpc_credcache_lock); -		return; +		if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) { +			cred->cr_expire = jiffies; +			list_add_tail(&cred->cr_lru, &cred_unused); +			number_cred_unused++; +			goto out_nodestroy; +		} +		if (!rpcauth_unhash_cred(cred)) { +			/* We were hashed and someone looked us up... */ +			goto out_nodestroy; +		}  	}  	spin_unlock(&rpc_credcache_lock); -out_destroy:  	cred->cr_ops->crdestroy(cred); +	return; +out_nodestroy: +	spin_unlock(&rpc_credcache_lock);  }  EXPORT_SYMBOL_GPL(put_rpccred);  | 
