forked from mirrors/linux
		
	sunrpc: never return expired entries in sunrpc_cache_lookup
If sunrpc_cache_lookup finds an expired entry, remove it from the cache and return a freshly created non-VALID entry instead. This ensures that we only ever get a usable entry, or an entry that will become usable once an update arrives. i.e. we will never need to repeat the lookup. This allows us to remove the 'is_expired' test from cache_check (i.e. from cache_is_valid). cache_check should never get an expired entry as 'lookup' will never return one. If it does happen - due to inconvenient timing - then just accept it as still valid, it won't be very much past it's use-by date. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
This commit is contained in:
		
							parent
							
								
									2f50d8b63d
								
							
						
					
					
						commit
						d202cce896
					
				
					 1 changed files with 14 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -59,7 +59,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 | 
			
		|||
				       struct cache_head *key, int hash)
 | 
			
		||||
{
 | 
			
		||||
	struct cache_head **head,  **hp;
 | 
			
		||||
	struct cache_head *new = NULL;
 | 
			
		||||
	struct cache_head *new = NULL, *freeme = NULL;
 | 
			
		||||
 | 
			
		||||
	head = &detail->hash_table[hash];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +68,9 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 | 
			
		|||
	for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
 | 
			
		||||
		struct cache_head *tmp = *hp;
 | 
			
		||||
		if (detail->match(tmp, key)) {
 | 
			
		||||
			if (cache_is_expired(detail, tmp))
 | 
			
		||||
				/* This entry is expired, we will discard it. */
 | 
			
		||||
				break;
 | 
			
		||||
			cache_get(tmp);
 | 
			
		||||
			read_unlock(&detail->hash_lock);
 | 
			
		||||
			return tmp;
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +95,13 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 | 
			
		|||
	for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
 | 
			
		||||
		struct cache_head *tmp = *hp;
 | 
			
		||||
		if (detail->match(tmp, key)) {
 | 
			
		||||
			if (cache_is_expired(detail, tmp)) {
 | 
			
		||||
				*hp = tmp->next;
 | 
			
		||||
				tmp->next = NULL;
 | 
			
		||||
				detail->entries --;
 | 
			
		||||
				freeme = tmp;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			cache_get(tmp);
 | 
			
		||||
			write_unlock(&detail->hash_lock);
 | 
			
		||||
			cache_put(new, detail);
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +114,8 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 | 
			
		|||
	cache_get(new);
 | 
			
		||||
	write_unlock(&detail->hash_lock);
 | 
			
		||||
 | 
			
		||||
	if (freeme)
 | 
			
		||||
		cache_put(freeme, detail);
 | 
			
		||||
	return new;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
 | 
			
		||||
| 
						 | 
				
			
			@ -189,8 +201,7 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
 | 
			
		|||
 | 
			
		||||
static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
 | 
			
		||||
{
 | 
			
		||||
	if (!test_bit(CACHE_VALID, &h->flags) ||
 | 
			
		||||
	    cache_is_expired(detail, h))
 | 
			
		||||
	if (!test_bit(CACHE_VALID, &h->flags))
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
	else {
 | 
			
		||||
		/* entry is valid */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue