diff options
| author | NeilBrown <neilb@suse.de> | 2006-03-27 01:15:02 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 08:44:41 -0800 | 
| commit | 15a5f6bd23eddd5b3be80366f364be04fb1c1c99 (patch) | |
| tree | e3c4fa8eb9e8b21ebca33370b7a93eab11662a5d | |
| parent | 7d317f2c9f1e9dcf4f632fa98f91d1d4a36c4cae (diff) | |
| download | olio-linux-3.10-15a5f6bd23eddd5b3be80366f364be04fb1c1c99.tar.xz olio-linux-3.10-15a5f6bd23eddd5b3be80366f364be04fb1c1c99.zip  | |
[PATCH] knfsd: Create cache_lookup function instead of using a macro to declare one
The C++-like 'template' approach proves to be too ugly and hard to work with.
The old 'template' won't go away until all users are updated.
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | include/linux/sunrpc/cache.h | 12 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 98 | 
2 files changed, 110 insertions, 0 deletions
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 405ac14e509..3e17a5ff1de 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -81,6 +81,11 @@ struct cache_detail {  					      struct cache_detail *cd,  					      struct cache_head *h); +	struct cache_head *	(*alloc)(void); +	int			(*match)(struct cache_head *orig, struct cache_head *new); +	void			(*init)(struct cache_head *orig, struct cache_head *new); +	void			(*update)(struct cache_head *orig, struct cache_head *new); +  	/* fields below this comment are for internal use  	 * and should not be touched by cache owners  	 */ @@ -237,6 +242,13 @@ RTN *FNAME ARGS										\  	& FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp),	\  	STRUCT##_init(new, item), STRUCT##_update(tmp, item)) +extern struct cache_head * +sunrpc_cache_lookup(struct cache_detail *detail, +		    struct cache_head *key, int hash); +extern struct cache_head * +sunrpc_cache_update(struct cache_detail *detail, +		    struct cache_head *new, struct cache_head *old, int hash); +  #define cache_for_each(pos, detail, index, member) 						\  	for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;		\ diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 0acccfeeb28..4449dc52edf 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -47,6 +47,104 @@ void cache_init(struct cache_head *h)  	h->last_refresh = now;  } +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; + +	head = &detail->hash_table[hash]; + +	read_lock(&detail->hash_lock); + +	for (hp=head; *hp != NULL ; hp = &(*hp)->next) { +		struct cache_head *tmp = *hp; +		if (detail->match(tmp, key)) { +			cache_get(tmp); +			read_unlock(&detail->hash_lock); +			return tmp; +		} +	} +	read_unlock(&detail->hash_lock); +	/* Didn't find anything, insert an empty entry */ + +	new = detail->alloc(); +	if (!new) +		return NULL; +	cache_init(new); + +	write_lock(&detail->hash_lock); + +	/* check if entry appeared while we slept */ +	for (hp=head; *hp != NULL ; hp = &(*hp)->next) { +		struct cache_head *tmp = *hp; +		if (detail->match(tmp, key)) { +			cache_get(tmp); +			write_unlock(&detail->hash_lock); +			detail->cache_put(new, detail); +			return tmp; +		} +	} +	detail->init(new, key); +	new->next = *head; +	*head = new; +	detail->entries++; +	cache_get(new); +	write_unlock(&detail->hash_lock); + +	return new; +} +EXPORT_SYMBOL(sunrpc_cache_lookup); + +struct cache_head *sunrpc_cache_update(struct cache_detail *detail, +				       struct cache_head *new, struct cache_head *old, int hash) +{ +	/* The 'old' entry is to be replaced by 'new'. +	 * If 'old' is not VALID, we update it directly, +	 * otherwise we need to replace it +	 */ +	struct cache_head **head; +	struct cache_head *tmp; + +	if (!test_bit(CACHE_VALID, &old->flags)) { +		write_lock(&detail->hash_lock); +		if (!test_bit(CACHE_VALID, &old->flags)) { +			if (test_bit(CACHE_NEGATIVE, &new->flags)) +				set_bit(CACHE_NEGATIVE, &old->flags); +			else +				detail->update(old, new); +			/* FIXME cache_fresh should come first */ +			write_unlock(&detail->hash_lock); +			cache_fresh(detail, old, new->expiry_time); +			return old; +		} +		write_unlock(&detail->hash_lock); +	} +	/* We need to insert a new entry */ +	tmp = detail->alloc(); +	if (!tmp) { +		detail->cache_put(old, detail); +		return NULL; +	} +	cache_init(tmp); +	detail->init(tmp, old); +	head = &detail->hash_table[hash]; + +	write_lock(&detail->hash_lock); +	if (test_bit(CACHE_NEGATIVE, &new->flags)) +		set_bit(CACHE_NEGATIVE, &tmp->flags); +	else +		detail->update(tmp, new); +	tmp->next = *head; +	*head = tmp; +	cache_get(tmp); +	write_unlock(&detail->hash_lock); +	cache_fresh(detail, tmp, new->expiry_time); +	cache_fresh(detail, old, 0); +	detail->cache_put(old, detail); +	return tmp; +} +EXPORT_SYMBOL(sunrpc_cache_update);  static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);  /*  |