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 *key, int hash)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cache_head **head,  **hp;
 | 
						struct cache_head **head,  **hp;
 | 
				
			||||||
	struct cache_head *new = NULL;
 | 
						struct cache_head *new = NULL, *freeme = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	head = &detail->hash_table[hash];
 | 
						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) {
 | 
						for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
 | 
				
			||||||
		struct cache_head *tmp = *hp;
 | 
							struct cache_head *tmp = *hp;
 | 
				
			||||||
		if (detail->match(tmp, key)) {
 | 
							if (detail->match(tmp, key)) {
 | 
				
			||||||
 | 
								if (cache_is_expired(detail, tmp))
 | 
				
			||||||
 | 
									/* This entry is expired, we will discard it. */
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
			cache_get(tmp);
 | 
								cache_get(tmp);
 | 
				
			||||||
			read_unlock(&detail->hash_lock);
 | 
								read_unlock(&detail->hash_lock);
 | 
				
			||||||
			return tmp;
 | 
								return tmp;
 | 
				
			||||||
| 
						 | 
					@ -92,6 +95,13 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 | 
				
			||||||
	for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
 | 
						for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
 | 
				
			||||||
		struct cache_head *tmp = *hp;
 | 
							struct cache_head *tmp = *hp;
 | 
				
			||||||
		if (detail->match(tmp, key)) {
 | 
							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);
 | 
								cache_get(tmp);
 | 
				
			||||||
			write_unlock(&detail->hash_lock);
 | 
								write_unlock(&detail->hash_lock);
 | 
				
			||||||
			cache_put(new, detail);
 | 
								cache_put(new, detail);
 | 
				
			||||||
| 
						 | 
					@ -104,6 +114,8 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 | 
				
			||||||
	cache_get(new);
 | 
						cache_get(new);
 | 
				
			||||||
	write_unlock(&detail->hash_lock);
 | 
						write_unlock(&detail->hash_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (freeme)
 | 
				
			||||||
 | 
							cache_put(freeme, detail);
 | 
				
			||||||
	return new;
 | 
						return new;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
 | 
					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)
 | 
					static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!test_bit(CACHE_VALID, &h->flags) ||
 | 
						if (!test_bit(CACHE_VALID, &h->flags))
 | 
				
			||||||
	    cache_is_expired(detail, h))
 | 
					 | 
				
			||||||
		return -EAGAIN;
 | 
							return -EAGAIN;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		/* entry is valid */
 | 
							/* entry is valid */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue