Commit c5b29f88 authored by NeilBrown's avatar NeilBrown Committed by J. Bruce Fields

sunrpc: use seconds since boot in expiry cache

This protects us from confusion when the wallclock time changes.

We convert to and from wallclock when  setting or reading expiry
times.

Also use seconds since boot for last_clost time.
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 17cebf65
...@@ -167,7 +167,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, ...@@ -167,7 +167,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
return 0; return 0;
} }
item = container_of(h, struct nfs_dns_ent, h); item = container_of(h, struct nfs_dns_ent, h);
ttl = (long)item->h.expiry_time - (long)get_seconds(); ttl = item->h.expiry_time - seconds_since_boot();
if (ttl < 0) if (ttl < 0)
ttl = 0; ttl = 0;
...@@ -239,7 +239,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) ...@@ -239,7 +239,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
ttl = get_expiry(&buf); ttl = get_expiry(&buf);
if (ttl == 0) if (ttl == 0)
goto out; goto out;
key.h.expiry_time = ttl + get_seconds(); key.h.expiry_time = ttl + seconds_since_boot();
ret = -ENOMEM; ret = -ENOMEM;
item = nfs_dns_lookup(cd, &key); item = nfs_dns_lookup(cd, &key);
...@@ -301,7 +301,7 @@ static int do_cache_lookup_nowait(struct cache_detail *cd, ...@@ -301,7 +301,7 @@ static int do_cache_lookup_nowait(struct cache_detail *cd,
goto out_err; goto out_err;
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
if (!test_bit(CACHE_VALID, &(*item)->h.flags) if (!test_bit(CACHE_VALID, &(*item)->h.flags)
|| (*item)->h.expiry_time < get_seconds() || (*item)->h.expiry_time < seconds_since_boot()
|| cd->flush_time > (*item)->h.last_refresh) || cd->flush_time > (*item)->h.last_refresh)
goto out_put; goto out_put;
ret = -ENOENT; ret = -ENOENT;
......
...@@ -550,7 +550,7 @@ do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *), ...@@ -550,7 +550,7 @@ do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *),
goto out_err; goto out_err;
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
if (!test_bit(CACHE_VALID, &(*item)->h.flags) if (!test_bit(CACHE_VALID, &(*item)->h.flags)
|| (*item)->h.expiry_time < get_seconds() || (*item)->h.expiry_time < seconds_since_boot()
|| detail->flush_time > (*item)->h.last_refresh) || detail->flush_time > (*item)->h.last_refresh)
goto out_put; goto out_put;
ret = -ENOENT; ret = -ENOENT;
......
...@@ -218,20 +218,42 @@ static inline int get_int(char **bpp, int *anint) ...@@ -218,20 +218,42 @@ static inline int get_int(char **bpp, int *anint)
return 0; return 0;
} }
/*
* timestamps kept in the cache are expressed in seconds
* since boot. This is the best for measuring differences in
* real time.
*/
static inline time_t seconds_since_boot(void)
{
struct timespec boot;
getboottime(&boot);
return get_seconds() - boot.tv_sec;
}
static inline time_t convert_to_wallclock(time_t sinceboot)
{
struct timespec boot;
getboottime(&boot);
return boot.tv_sec + sinceboot;
}
static inline time_t get_expiry(char **bpp) static inline time_t get_expiry(char **bpp)
{ {
int rv; int rv;
struct timespec boot;
if (get_int(bpp, &rv)) if (get_int(bpp, &rv))
return 0; return 0;
if (rv < 0) if (rv < 0)
return 0; return 0;
return rv; getboottime(&boot);
return rv - boot.tv_sec;
} }
static inline void sunrpc_invalidate(struct cache_head *h, static inline void sunrpc_invalidate(struct cache_head *h,
struct cache_detail *detail) struct cache_detail *detail)
{ {
h->expiry_time = get_seconds() - 1; h->expiry_time = seconds_since_boot() - 1;
detail->nextcheck = get_seconds(); detail->nextcheck = seconds_since_boot();
} }
#endif /* _LINUX_SUNRPC_CACHE_H_ */ #endif /* _LINUX_SUNRPC_CACHE_H_ */
...@@ -42,7 +42,7 @@ static void cache_revisit_request(struct cache_head *item); ...@@ -42,7 +42,7 @@ 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)
{ {
time_t now = get_seconds(); time_t now = seconds_since_boot();
h->next = NULL; h->next = NULL;
h->flags = 0; h->flags = 0;
kref_init(&h->ref); kref_init(&h->ref);
...@@ -52,7 +52,7 @@ static void cache_init(struct cache_head *h) ...@@ -52,7 +52,7 @@ static void cache_init(struct cache_head *h)
static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
{ {
return (h->expiry_time < get_seconds()) || return (h->expiry_time < seconds_since_boot()) ||
(detail->flush_time > h->last_refresh); (detail->flush_time > h->last_refresh);
} }
...@@ -127,7 +127,7 @@ static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); ...@@ -127,7 +127,7 @@ 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)
{ {
head->expiry_time = expiry; head->expiry_time = expiry;
head->last_refresh = get_seconds(); head->last_refresh = seconds_since_boot();
set_bit(CACHE_VALID, &head->flags); set_bit(CACHE_VALID, &head->flags);
} }
...@@ -238,7 +238,7 @@ int cache_check(struct cache_detail *detail, ...@@ -238,7 +238,7 @@ int cache_check(struct cache_detail *detail,
/* now see if we want to start an upcall */ /* now see if we want to start an upcall */
refresh_age = (h->expiry_time - h->last_refresh); refresh_age = (h->expiry_time - h->last_refresh);
age = get_seconds() - h->last_refresh; age = seconds_since_boot() - h->last_refresh;
if (rqstp == NULL) { if (rqstp == NULL) {
if (rv == -EAGAIN) if (rv == -EAGAIN)
...@@ -253,7 +253,7 @@ int cache_check(struct cache_detail *detail, ...@@ -253,7 +253,7 @@ int cache_check(struct cache_detail *detail,
cache_revisit_request(h); cache_revisit_request(h);
if (rv == -EAGAIN) { if (rv == -EAGAIN) {
set_bit(CACHE_NEGATIVE, &h->flags); set_bit(CACHE_NEGATIVE, &h->flags);
cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY); cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
cache_fresh_unlocked(h, detail); cache_fresh_unlocked(h, detail);
rv = -ENOENT; rv = -ENOENT;
} }
...@@ -388,11 +388,11 @@ static int cache_clean(void) ...@@ -388,11 +388,11 @@ static int cache_clean(void)
return -1; return -1;
} }
current_detail = list_entry(next, struct cache_detail, others); current_detail = list_entry(next, struct cache_detail, others);
if (current_detail->nextcheck > get_seconds()) if (current_detail->nextcheck > seconds_since_boot())
current_index = current_detail->hash_size; current_index = current_detail->hash_size;
else { else {
current_index = 0; current_index = 0;
current_detail->nextcheck = get_seconds()+30*60; current_detail->nextcheck = seconds_since_boot()+30*60;
} }
} }
...@@ -477,7 +477,7 @@ EXPORT_SYMBOL_GPL(cache_flush); ...@@ -477,7 +477,7 @@ EXPORT_SYMBOL_GPL(cache_flush);
void cache_purge(struct cache_detail *detail) void cache_purge(struct cache_detail *detail)
{ {
detail->flush_time = LONG_MAX; detail->flush_time = LONG_MAX;
detail->nextcheck = get_seconds(); detail->nextcheck = seconds_since_boot();
cache_flush(); cache_flush();
detail->flush_time = 1; detail->flush_time = 1;
} }
...@@ -902,7 +902,7 @@ static int cache_release(struct inode *inode, struct file *filp, ...@@ -902,7 +902,7 @@ static int cache_release(struct inode *inode, struct file *filp,
filp->private_data = NULL; filp->private_data = NULL;
kfree(rp); kfree(rp);
cd->last_close = get_seconds(); cd->last_close = seconds_since_boot();
atomic_dec(&cd->readers); atomic_dec(&cd->readers);
} }
module_put(cd->owner); module_put(cd->owner);
...@@ -1034,7 +1034,7 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h, ...@@ -1034,7 +1034,7 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
int len; int len;
if (atomic_read(&detail->readers) == 0 && if (atomic_read(&detail->readers) == 0 &&
detail->last_close < get_seconds() - 30) { detail->last_close < seconds_since_boot() - 30) {
warn_no_listener(detail); warn_no_listener(detail);
return -EINVAL; return -EINVAL;
} }
...@@ -1219,7 +1219,8 @@ static int c_show(struct seq_file *m, void *p) ...@@ -1219,7 +1219,8 @@ static int c_show(struct seq_file *m, void *p)
ifdebug(CACHE) ifdebug(CACHE)
seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags); convert_to_wallclock(cp->expiry_time),
atomic_read(&cp->ref.refcount), cp->flags);
cache_get(cp); cache_get(cp);
if (cache_check(cd, cp, NULL)) if (cache_check(cd, cp, NULL))
/* cache_check does a cache_put on failure */ /* cache_check does a cache_put on failure */
...@@ -1285,7 +1286,7 @@ static ssize_t read_flush(struct file *file, char __user *buf, ...@@ -1285,7 +1286,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
unsigned long p = *ppos; unsigned long p = *ppos;
size_t len; size_t len;
sprintf(tbuf, "%lu\n", cd->flush_time); sprintf(tbuf, "%lu\n", convert_to_wallclock(cd->flush_time));
len = strlen(tbuf); len = strlen(tbuf);
if (p >= len) if (p >= len)
return 0; return 0;
...@@ -1303,19 +1304,20 @@ static ssize_t write_flush(struct file *file, const char __user *buf, ...@@ -1303,19 +1304,20 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
struct cache_detail *cd) struct cache_detail *cd)
{ {
char tbuf[20]; char tbuf[20];
char *ep; char *bp, *ep;
long flushtime;
if (*ppos || count > sizeof(tbuf)-1) if (*ppos || count > sizeof(tbuf)-1)
return -EINVAL; return -EINVAL;
if (copy_from_user(tbuf, buf, count)) if (copy_from_user(tbuf, buf, count))
return -EFAULT; return -EFAULT;
tbuf[count] = 0; tbuf[count] = 0;
flushtime = simple_strtoul(tbuf, &ep, 0); simple_strtoul(tbuf, &ep, 0);
if (*ep && *ep != '\n') if (*ep && *ep != '\n')
return -EINVAL; return -EINVAL;
cd->flush_time = flushtime; bp = tbuf;
cd->nextcheck = get_seconds(); cd->flush_time = get_expiry(&bp);
cd->nextcheck = seconds_since_boot();
cache_flush(); cache_flush();
*ppos += count; *ppos += count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment