static void cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
-void cache_init(struct cache_head *h)
+static void cache_init(struct cache_head *h)
{
time_t now = get_seconds();
h->next = NULL;
h->flags = 0;
- atomic_set(&h->refcnt, 1);
+ kref_init(&h->ref);
h->expiry_time = now + CACHE_NEW_EXPIRY;
h->last_refresh = now;
}
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);
if (detail->match(tmp, key)) {
cache_get(tmp);
write_unlock(&detail->hash_lock);
- detail->cache_put(new, detail);
+ cache_put(new, detail);
return tmp;
}
}
- detail->init(new, key);
new->next = *head;
*head = new;
detail->entries++;
}
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)
{
*/
struct cache_head **head;
struct cache_head *tmp;
+ int is_new;
if (!test_bit(CACHE_VALID, &old->flags)) {
write_lock(&detail->hash_lock);
set_bit(CACHE_NEGATIVE, &old->flags);
else
detail->update(old, new);
- /* FIXME cache_fresh should come first */
+ is_new = cache_fresh_locked(old, new->expiry_time);
write_unlock(&detail->hash_lock);
- cache_fresh(detail, old, new->expiry_time);
+ 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) {
- detail->cache_put(old, detail);
+ cache_put(old, detail);
return NULL;
}
cache_init(tmp);
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(detail, tmp, new->expiry_time);
- cache_fresh(detail, old, 0);
- detail->cache_put(old, detail);
+ cache_fresh_unlocked(tmp, detail, is_new);
+ cache_fresh_unlocked(old, detail, 0);
+ cache_put(old, detail);
return tmp;
}
EXPORT_SYMBOL(sunrpc_cache_update);
clear_bit(CACHE_PENDING, &h->flags);
if (rv == -EAGAIN) {
set_bit(CACHE_NEGATIVE, &h->flags);
- cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY);
+ cache_fresh_unlocked(h, detail,
+ cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY));
rv = -ENOENT;
}
break;
if (rv == -EAGAIN)
cache_defer_req(rqstp, h);
- if (rv && h)
- detail->cache_put(h, detail);
+ if (rv)
+ cache_put(h, detail);
return rv;
}
-static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
-
-void cache_fresh(struct cache_detail *detail,
- struct cache_head *head, time_t expiry)
-{
-
- head->expiry_time = expiry;
- head->last_refresh = get_seconds();
- if (!test_and_set_bit(CACHE_VALID, &head->flags))
- cache_revisit_request(head);
- if (test_and_clear_bit(CACHE_PENDING, &head->flags))
- queue_loose(detail, head);
-}
-
/*
* caches need to be periodically cleaned.
* For this we maintain a list of cache_detail and
if (test_and_clear_bit(CACHE_PENDING, &ch->flags))
queue_loose(current_detail, ch);
- if (atomic_read(&ch->refcnt) == 1)
+ if (atomic_read(&ch->ref.refcount) == 1)
break;
}
if (ch) {
current_index ++;
spin_unlock(&cache_list_lock);
if (ch)
- d->cache_put(ch, d);
+ cache_put(ch, d);
} else
spin_unlock(&cache_list_lock);
/* there was one too many */
dreq->revisit(dreq, 1);
}
- if (test_bit(CACHE_VALID, &item->flags)) {
+ if (!test_bit(CACHE_PENDING, &item->flags)) {
/* must have just been validated... */
cache_revisit_request(item);
}
!test_bit(CACHE_PENDING, &rq->item->flags)) {
list_del(&rq->q.list);
spin_unlock(&queue_lock);
- cd->cache_put(rq->item, cd);
+ cache_put(rq->item, cd);
kfree(rq->buf);
kfree(rq);
} else
if (cr->item != ch)
continue;
if (cr->readers != 0)
- break;
+ continue;
list_del(&cr->q.list);
spin_unlock(&queue_lock);
- detail->cache_put(cr->item, detail);
+ cache_put(cr->item, detail);
kfree(cr->buf);
kfree(cr);
return;
return cd->cache_show(m, cd, NULL);
ifdebug(CACHE)
- seq_printf(m, "# expiry=%ld refcnt=%d\n",
- cp->expiry_time, atomic_read(&cp->refcnt));
+ seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
+ cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags);
cache_get(cp);
if (cache_check(cd, cp, NULL))
/* cache_check does a cache_put on failure */