/* * This is the generic cache management routine for all * the authentication caches. * It checks the currency of a cache item and will (later) * initiate an upcall to fill it if needed. * * * Returns 0 if the cache_head can be used, or cache_puts it and returns * -EAGAIN if upcall is pending, * -ENOENT if cache entry was negative */ int cache_check(struct cache_detail *detail, struct cache_head *h, struct cache_req *rqstp) { int rv; long refresh_age, age; /* First decide return status as best we can */ if (!test_bit(CACHE_VALID, &h->flags) || h->expiry_time < get_seconds()) rv = -EAGAIN; else if (detail->flush_time > h->last_refresh) rv = -EAGAIN; else { /* entry is valid */ if (test_bit(CACHE_NEGATIVE, &h->flags)) rv = -ENOENT; else rv = 0; } /* now see if we want to start an upcall */ refresh_age = (h->expiry_time - h->last_refresh); age = get_seconds() - h->last_refresh; if (rqstp == NULL) { if (rv == -EAGAIN) rv = -ENOENT; } else if (rv == -EAGAIN || age > refresh_age/2) { dprintk("Want update, refage=%ld, age=%ld\n", refresh_age, age); if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { switch (cache_make_upcall(detail, h)) { case -EINVAL: clear_bit(CACHE_PENDING, &h->flags); if (rv == -EAGAIN) { set_bit(CACHE_NEGATIVE, &h->flags); cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY); rv = -ENOENT; } break; case -EAGAIN: clear_bit(CACHE_PENDING, &h->flags); cache_revisit_request(h); break; } } } if (rv == -EAGAIN) cache_defer_req(rqstp, h); if (rv && h) detail->cache_put(h, detail); return rv; }
struct auth_domain * auth_domain_lookup(struct auth_domain *item, int set) { struct auth_domain *tmp = NULL; struct cache_head **hp, **head; head = &auth_domain_cache.hash_table[auth_domain_hash(item)]; if (set) write_lock(&auth_domain_cache.hash_lock); else read_lock(&auth_domain_cache.hash_lock); for (hp=head; *hp != NULL; hp = &tmp->h.next) { tmp = container_of(*hp, struct auth_domain, h); if (!auth_domain_match(tmp, item)) continue; cache_get(&tmp->h); if (!set) goto out_noset; *hp = tmp->h.next; tmp->h.next = NULL; clear_bit(CACHE_HASHED, &tmp->h.flags); auth_domain_drop(&tmp->h, &auth_domain_cache); goto out_set; } /* Didn't find anything */ if (!set) goto out_nada; auth_domain_cache.entries++; out_set: set_bit(CACHE_HASHED, &item->h.flags); item->h.next = *head; *head = &item->h; write_unlock(&auth_domain_cache.hash_lock); cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time); cache_get(&item->h); return item; out_nada: tmp = NULL; out_noset: read_unlock(&auth_domain_cache.hash_lock); return tmp; }