|
@@ -41,13 +41,16 @@
|
|
|
static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
|
|
|
static void cache_revisit_request(struct cache_head *item);
|
|
|
|
|
|
-static void cache_init(struct cache_head *h)
|
|
|
+static void cache_init(struct cache_head *h, struct cache_detail *detail)
|
|
|
{
|
|
|
time_t now = seconds_since_boot();
|
|
|
INIT_HLIST_NODE(&h->cache_list);
|
|
|
h->flags = 0;
|
|
|
kref_init(&h->ref);
|
|
|
h->expiry_time = now + CACHE_NEW_EXPIRY;
|
|
|
+ if (now <= detail->flush_time)
|
|
|
+ /* ensure it isn't already expired */
|
|
|
+ now = detail->flush_time + 1;
|
|
|
h->last_refresh = now;
|
|
|
}
|
|
|
|
|
@@ -81,7 +84,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
|
|
|
* we might get lose if we need to
|
|
|
* cache_put it soon.
|
|
|
*/
|
|
|
- cache_init(new);
|
|
|
+ cache_init(new, detail);
|
|
|
detail->init(new, key);
|
|
|
|
|
|
write_lock(&detail->hash_lock);
|
|
@@ -116,10 +119,15 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
|
|
|
|
|
|
static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
|
|
|
|
|
|
-static void cache_fresh_locked(struct cache_head *head, time_t expiry)
|
|
|
+static void cache_fresh_locked(struct cache_head *head, time_t expiry,
|
|
|
+ struct cache_detail *detail)
|
|
|
{
|
|
|
+ time_t now = seconds_since_boot();
|
|
|
+ if (now <= detail->flush_time)
|
|
|
+ /* ensure it isn't immediately treated as expired */
|
|
|
+ now = detail->flush_time + 1;
|
|
|
head->expiry_time = expiry;
|
|
|
- head->last_refresh = seconds_since_boot();
|
|
|
+ head->last_refresh = now;
|
|
|
smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
|
|
|
set_bit(CACHE_VALID, &head->flags);
|
|
|
}
|
|
@@ -149,7 +157,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
|
|
|
set_bit(CACHE_NEGATIVE, &old->flags);
|
|
|
else
|
|
|
detail->update(old, new);
|
|
|
- cache_fresh_locked(old, new->expiry_time);
|
|
|
+ cache_fresh_locked(old, new->expiry_time, detail);
|
|
|
write_unlock(&detail->hash_lock);
|
|
|
cache_fresh_unlocked(old, detail);
|
|
|
return old;
|
|
@@ -162,7 +170,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
|
|
|
cache_put(old, detail);
|
|
|
return NULL;
|
|
|
}
|
|
|
- cache_init(tmp);
|
|
|
+ cache_init(tmp, detail);
|
|
|
detail->init(tmp, old);
|
|
|
|
|
|
write_lock(&detail->hash_lock);
|
|
@@ -173,8 +181,8 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
|
|
|
hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]);
|
|
|
detail->entries++;
|
|
|
cache_get(tmp);
|
|
|
- cache_fresh_locked(tmp, new->expiry_time);
|
|
|
- cache_fresh_locked(old, 0);
|
|
|
+ cache_fresh_locked(tmp, new->expiry_time, detail);
|
|
|
+ cache_fresh_locked(old, 0, detail);
|
|
|
write_unlock(&detail->hash_lock);
|
|
|
cache_fresh_unlocked(tmp, detail);
|
|
|
cache_fresh_unlocked(old, detail);
|
|
@@ -219,7 +227,8 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h
|
|
|
rv = cache_is_valid(h);
|
|
|
if (rv == -EAGAIN) {
|
|
|
set_bit(CACHE_NEGATIVE, &h->flags);
|
|
|
- cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
|
|
|
+ cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY,
|
|
|
+ detail);
|
|
|
rv = -ENOENT;
|
|
|
}
|
|
|
write_unlock(&detail->hash_lock);
|
|
@@ -487,10 +496,13 @@ EXPORT_SYMBOL_GPL(cache_flush);
|
|
|
|
|
|
void cache_purge(struct cache_detail *detail)
|
|
|
{
|
|
|
- detail->flush_time = LONG_MAX;
|
|
|
+ time_t now = seconds_since_boot();
|
|
|
+ if (detail->flush_time >= now)
|
|
|
+ now = detail->flush_time + 1;
|
|
|
+ /* 'now' is the maximum value any 'last_refresh' can have */
|
|
|
+ detail->flush_time = now;
|
|
|
detail->nextcheck = seconds_since_boot();
|
|
|
cache_flush();
|
|
|
- detail->flush_time = 1;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(cache_purge);
|
|
|
|
|
@@ -1436,6 +1448,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
|
|
|
{
|
|
|
char tbuf[20];
|
|
|
char *bp, *ep;
|
|
|
+ time_t then, now;
|
|
|
|
|
|
if (*ppos || count > sizeof(tbuf)-1)
|
|
|
return -EINVAL;
|
|
@@ -1447,8 +1460,22 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
|
|
|
return -EINVAL;
|
|
|
|
|
|
bp = tbuf;
|
|
|
- cd->flush_time = get_expiry(&bp);
|
|
|
- cd->nextcheck = seconds_since_boot();
|
|
|
+ then = get_expiry(&bp);
|
|
|
+ now = seconds_since_boot();
|
|
|
+ cd->nextcheck = now;
|
|
|
+ /* Can only set flush_time to 1 second beyond "now", or
|
|
|
+ * possibly 1 second beyond flushtime. This is because
|
|
|
+ * flush_time never goes backwards so it mustn't get too far
|
|
|
+ * ahead of time.
|
|
|
+ */
|
|
|
+ if (then >= now) {
|
|
|
+ /* Want to flush everything, so behave like cache_purge() */
|
|
|
+ if (cd->flush_time >= now)
|
|
|
+ now = cd->flush_time + 1;
|
|
|
+ then = now;
|
|
|
+ }
|
|
|
+
|
|
|
+ cd->flush_time = then;
|
|
|
cache_flush();
|
|
|
|
|
|
*ppos += count;
|