[PATCH] knfsd: Create cache_lookup function instead of using a macro to declare one
authorNeilBrown <neilb@suse.de>
Mon, 27 Mar 2006 09:15:02 +0000 (01:15 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 27 Mar 2006 16:44:41 +0000 (08:44 -0800)
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>
include/linux/sunrpc/cache.h
net/sunrpc/cache.c

index 405ac14..3e17a5f 100644 (file)
@@ -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;}) ;                \
index 0acccfe..4449dc5 100644 (file)
@@ -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);
 /*