-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;
- /* must fully initialise 'new', else
- * we might get lose if we need to
- * cache_put it soon.
- */
- cache_init(new);
- detail->init(new, key);
-
- 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);
- cache_put(new, detail);
- return tmp;
- }
- }
- new->next = *head;
- *head = new;
- detail->entries++;
- cache_get(new);
- write_unlock(&detail->hash_lock);
-
- return new;
-}
-EXPORT_SYMBOL(sunrpc_cache_lookup);
-
-
-static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
-
-static int cache_fresh_locked(struct cache_head *head, time_t expiry)
-{
- head->expiry_time = expiry;
- head->last_refresh = get_seconds();
- return !test_and_set_bit(CACHE_VALID, &head->flags);
-}
-
-static void cache_fresh_unlocked(struct cache_head *head,
- struct cache_detail *detail, int new)
-{
- if (new)
- cache_revisit_request(head);
- if (test_and_clear_bit(CACHE_PENDING, &head->flags)) {
- cache_revisit_request(head);
- queue_loose(detail, head);
- }
-}
-
-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;
- int is_new;
-
- 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);
- is_new = cache_fresh_locked(old, new->expiry_time);
- write_unlock(&detail->hash_lock);
- cache_fresh_unlocked(old, detail, is_new);
- return old;
- }
- write_unlock(&detail->hash_lock);
- }
- /* We need to insert a new entry */
- tmp = detail->alloc();
- if (!tmp) {
- 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;
- detail->entries++;
- cache_get(tmp);
- is_new = cache_fresh_locked(tmp, new->expiry_time);
- cache_fresh_locked(old, 0);
- write_unlock(&detail->hash_lock);
- cache_fresh_unlocked(tmp, detail, is_new);
- cache_fresh_unlocked(old, detail, 0);
- cache_put(old, detail);
- return tmp;
-}
-EXPORT_SYMBOL(sunrpc_cache_update);